Ruby objects are strictly encapsulated: they can only access their internal states through defined methods. The member variables used by the method cannot be directly accessed outside the object. However, they can be directly accessed through getter, setter, and other accessors (accessor.
In contrast to the encapsulation of object states, classes in ruby are very open. Every Ruby program can add methods for existing classes, and can also add "Singleton method" to a single object )".
Create class
Classes are created in Ruby with the class Keyword:
Class Point
End
Like most Ruby constructs, a class definition is delimited with an end. In addition
Defining a new class, the class keyword creates a new constant to refer to the class.
Class Name and the constant name are the same, so all class names must begin with
Capital letter.
Within the body of a class, but outside of any instance methods defined by the class,
The self keyword refer
CThe lass keyword also creates a constant to reference this class. This constant name is the same as the class name, so all class names must begin with an uppercase letter. (Because the constant name must start with an uppercase letter ).
An error will be reported when writing the code as class:
Class/Module name must be constant
Like the vast majority of Ruby statements, class is an expression. The class expression gets the value equal to the value of the last expression in the class definition body. In general, the last expression of the class is a Def statement used to define the method, and the value of the def statement is always equal to nil.
Instantiate a Point Object
P = point. New
The constant point holds a class object that represents our new class. All class objects
Have a method named new that creates a new instance.
A constant point represents a Class Object. All class objects have a new method.
We can't do anything very interesting with the newly created point object we 've ve stored
In the local variable P, Because we haven't yet defined any methods for the class. We
Can, however, ask the new object what kind of object it is:
P. class # => point
P. is_a? Point #=> true
Initialization
Implemented through initialize
class Point def initialize(x,y) @x,@y=x,y endend
An instance method is defined here. When an instance method is called, the value of self represents the instance.
The new method of the Class Object creates an instantiation, automatically calls the initialize method of the instance, and all parameters passed to the new method are passed to the initialize method.
In addition to being automatically called by point. New, the initialize method automatically becomes a private method of the class. The object itself can call the initialize method, but it cannot explicitly call initialize on P to reinitialize its status..
Define the to_s Method
Any custom class should define a to_s method, which is very useful in debugging. The following shows how to define this method for a point.
class Point def initialize(x,y) @x,@y=x,y end def to_s "(#@x,#@y)" end end
We can call
Puts P
Accessors and attributes
Define getter:
def x @x def y @y
If you want the Point class to become a mutable class, you can add the setter method.
class Point def initialize(x,y) @x,@y=x,y end def to_s "(#@x,#@y)" end def x;@x;end def y;@y;end def x=(value) @x=value end def y=(value) @y=value end end
This can be called as follows:
P = point. New (1, 2)
P. x = 0
P. Y = 0
Once a writer method like x = is defined, you may try to use them in the instance method. That is to say, you want to use X = 2 to call X = (2) instead of @ x = 2. however, this is not acceptable. x = 2 will only create a new local variable.
This is a common mistake for beginners. Only when a value expression is used for an object will the method of writing it be called. If you want to use this writer method in the class that defines the writer method, you must explicitly call it through self, for example, self. x = 2.
This combination of instance variable with trivial getter and setter methods is so common
That ruby provides a way to automate it. The attr_reader and attr_accessor
Methods are defined by the module class. All classes are modules, (the class is
Subclass of module) so you can invoke these method inside any class definition. Both
Methods take any number of symbols naming attributes. attr_reader creates trivial
Getter methods for the instance variables with the same name. attr_accessor creates
Getter and setter methods. Thus, if we were defining a mutable Point class, we cocould
Write:
The module has the attr_reade and attr_accessor methods. Because all classes are modules (the class is a subclass of the module), you can call these methods in any class instance. Each method accepts any number of characters (used as the attribute name) as the parameter. atrtr_reader creates a reader method with the same name for the instance variable with the given name,
Define variable classes:
Class Point
Attr_accessor: X,: y # define accessor methods for our instance variables
End
Defines an unchangeable class:
And if we were defining an immutable version of the class, we 'd write:
Class Point
Attr_reader: X,: y # define reader methods for our instance variables
End
Each of these methods can accept an attribute name or names as a string rather
As a symbol. The accepted style is to use symbols, but we can also write code like this:
Attr_reader "X", "Y"
The attr_reader and attr_accessor methods can be used to create an instance for us. This is an example of metaprogramming. He demonstrated a powerful Ruby feature. Note that ATTR methods are called within the class definition so that they are executed only once during the class definition. There is no efficiency problem here: the readers and writers created in this way are as fast as hard-coded.
Defining Operators
We 'd like the + operator to perform Vector Addition of two point objects, the * operator
To multiply a point by a scalar, And the Unary-operator to do the equivalent of multiplying
By-1. method-based operators such as + are simply methods with punctuation
For names. Because there are unary and binary forms of the-operator, Ruby uses
Method Name-@ for unary minus. The minus sign has one and two elements. [Email protected] indicates one dollar. Here is a version of the Point class with mathematical
Operators defined:
class Point attr_reader :x, :y # Define accessor methods for our instance variables def initialize(x,y) @x,@y=x,y end def +(other) # Define + to do vector addition Point.new(@x + other.x, @y + other.y) end def [email protected] # Define unary minus to negate both coordinates Point.new([email protected], -@y) end def *(scalar) # Define * to perform scalar multiplication Point.new(@x*scalar, @y*scalar) endend
Note that the * method we define requires a numerical parameter instead of a point object. If P is a vertex, p * 2 is allowed. However, due to our implementation method, 2 * P cannot work normally. If you want 2 * P and p * 2 to return the same result, you can define a coerce method:
# If we try passing a point to the * method of an integer, it will call
# This method on the point and then will try to multiply the elements
# The array. Instead of doing type conversion, we switch the order
# The operands, so that we invoke the * method defined above.
Def coerce (other)
[Self, other]
End
Array and hash access with []
Ruby uses square brackets for Array and hash access, and allows any class to define
[] Method and use these brackets itself. Let's define a [] Method for our class to allow
Point objects to be treated as read-only arrays of length 2, or as read-only hashes
Keys: X and: Y:
def [](index) case index when 0, -2 then @x when 1,-1 then @y when :x,"x" then @x when :y,"y" then @y else nil end end
Enumerating coordinates enumeration coordinates
If a point object can behave like an array with two elements, then perhaps we ought tobe able to iterate through those elements as we can with a true array. Here is a definition
Of the each iterator for our point class. Because a point always has exactly two elements,
Our iterator doesn' t have to loop; it can simply call yield twice: because the point only has two elements, there is no need to loop, just call yield twice.
# This iterator passes the X coordinate to the associated block, and then
# Passes the Y coordinate, and then returns. It allows us to enumerate
# A point as if it were an array with two elements. This each method is
# Required by the enumerable module.
Def each
Yield @ x
Yield @ Y
End
With this iterator defined, we can write code like this:
P = point. New (1, 2)
P. Each {| x | print x} # prints "12"
More importantly, once the each iterator is defined, we can mix some methods of the enumerable module. These methods are all defined based on each. In this way, by adding the following line of code, he will get more than 20 iterators:
Include enumerable
If this line of code is added, we can write the following interesting code:
# Is the point P AT THE ORIGIN
P. All? {| X = 0} # true if the block is true for all elems