> For the complete documentation index, see [llms.txt](https://huang-jason.gitbook.io/ruby-rails-syntax/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://huang-jason.gitbook.io/ruby-rails-syntax/chap_1.md).

# chap 1

## attr\_\*

attr\_accessor :engine allows you to read AND write to the variable @engine.

attr\_reader :engine only allows you to read the value of @engine

```ruby
attr_writer :age
# up is equal to bottom.
def age=(value)
  @age = value
end
```

```ruby
attr_reader :age
# up is equal to bottom.
def age
  @age
end
```

```ruby
attr_accessor :age
# up is equal to bottom.
def age=(value)
  @age = value
end

def age
  @age
end
```

## virtual attribute/ setter / :method=

`:method=` assign attributes by `=`

`:method` assign attributes by `()`

```ruby
class Foo
  def foo=(x)
    puts "OK: x=#{x}"
  end

  def poo(y)
    puts "KO: y=#{y}"
  end
end
f = Foo.new
f.foo = 123 # => 123
# OK: x=123
f.poo(123)
# KO: y=123
```

## use `var` & `@var` in class

1. With `attr_reader` inside class, you can use both `element` & `@element`.
2. Without `attr_reader` inside class, you can use only `@element`.

```ruby
class Person
  attr_reader :element # make different
  def initialize(element)
    @element = element
  end

  def at
      puts @element
  end

  def woat
    puts element
  end
end

gina = Person.new("Gina")

gina.at   # Gina
gina.woat # Gina
```

```ruby
class People

  def initialize(element)
    @element = element
  end

  def at
      puts @element
  end

  def woat
    puts element
  end
end

jason = People.new("Jason")

jason.at   # Jason
jason.woat # rb:12 undefined local variable or method `element'
```

## &:symbol

block: `{...}` or `do ... end`

`Proc`: set block as a variable.

`&Proc`: return the original block.

```ruby
my_proc = Proc.new { puts "foo" }
# => #<Proc:0x0012345677(irb):99> 
my_method_call(&my_proc) # is identical to:
my_method_call { puts "foo" }
```

```ruby
# people.collect { |p| p.name }
people.collect(&:name)

# people.select { |p| p.manager? }.collect { |p| p.salary }
people.select(&:manager?).collect(&:salary)
```

Difference between `Proc` and `lambda`:\
1\. `lambda` checks **argument numbers**, and `Proc` not.\
2\. `return` in `lambda` means "leaving lambda"; `return` in `Proc` means "leaving the **method**.

## `define_method(*args)`

Defines an instance method for the receiver: args.

```ruby
class A
  def fred
    puts "In Fred"
  end
  def create_method(name, &block)
    self.class.send(:define_method, name, &block)
  end
  define_method(:wilma) { puts "Charge it!" }
end
class B < A
  define_method(:barney, instance_method(:fred))
end
a = B.new
a.barney
a.wilma
a.create_method(:betty) { p self }
a.betty
```

```ruby
In Fred
Charge it!
#<B:0x401b39e8>
```

## `constantize(str)`

tries to find a declared constant with the name specified in the string.

```
'Module'.constantize  # => Module
'Class'.constantize   # => Class
'blargle'.constantize # => NameError: wrong constant name blargle
```

## Inject and Reduce

`Inject` and `Reduce` are the same.

```ruby
# Sum some numbers
(5..10).reduce(:+)                            #=> 45
# Same using a block and inject
(5..10).inject {|sum, n| sum + n }            #=> 45
# Multiply some numbers
(5..10).reduce(1, :*)                         #=> 151200
# Same using a block
(5..10).inject(1) {|product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo,word|
   memo.length > word.length ? memo : word
end
longest                                       #=> "sheep"
```

```ruby
(1..10).inject(:+) # 55
(1..10).reduce(:+) # 55

def sum(start = 0)
  inject(start, &:+)
end
(1..10).sum # 55
```

## File

```ruby
__FILE__ # the current source file name.
__LINE__ # the current line number in the source file.
```

```ruby
File.dirname(__FILE__) # "."
File.expand_path(File.dirname(__FILE__))
# /Users/jasonych99/workspace/ROR/RULER/rulers
File.join(File.dirname(__FILE__), "..", "lib") # "./../lib"
```

The second param is the starting point for the first one in `File.expand_path`.

```ruby
File.expand_path(__FILE__)
 => "/Users/jasonych99/workspace/ROR/RULER/rulers/(irb)"
File.expand_path("../../assets/base.css", __FILE__)
 => "/Users/jasonych99/workspace/ROR/RULER/assets/base.css"
```

`$0` = name of the script being **executed**.

For example, when running ruby hello\_world.rb, $0 = hello\_world.

```ruby
__FILE__ == $0 
# the source code file == the file I'm executing!
```

reference: <http://periclestheo.com/2014/02/what-is-up-with-__FILE__-and-$0.html>

## const\_get / send (fetch class/method by "string" or :sym)

check and return the constant

```ruby
const_get(:sym)
const_get("string")
Math.const_get(:PI)   #=> 3.14159265358979
```

Invoke the method

```ruby
obj.send(:sym)
obj.send("string")
```

```ruby
class Person
  def initialize(name)
    @name = name
  end

  def name
    @name
  end

  def oui
    "My name is #{@name}"
  end
end

target = Object.const_get("Person") # Person
target.class # Class

obj = Person.new("Jason") # #<Person:0x007f9012999248 @name="Jason">
obj.oui # "My name is Jason"
obj.send(:oui)  # "My name is Jason"
obj.send("oui") # "My name is Jason"
```

## include / extend

`include` provides **instance methods** for the class that mixes it in.

`extend` provides **class methods** for the class that mixes it in.

```ruby
module Foo
  def foo
    puts 'heyyyyoooo!'
  end
end

class Bar
  include Foo
end

Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class

class Baz
  extend Foo
end

Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>
```
