--Metaprogramming is to write the code that writes the code.
In programming and Ruby, introspection is generally the ability to see objects, classes, etc. at runtime to know them.
Example:
#Below is the class definition
class A
def a; end
end
module B
def b; end
end
class C < A
include B
def c; end
end
##Introspection
# Q.What is a C instance method?
# A. C.instance_methods # [:c, :b, :a, :to_json, :instance_of?...]
# Q.What is an instance method that declares only C?
# A. C.instance_methods(false) # [:c]
# Q.What are Class C ancestors?
# A. C.ancestors # [C, B, A, Object,...]
# Q.C super class?
# A. C.superclass # A
--You want to create an ORM class.
# the_m_word/orm.rb
class Entity
attr_reader :table, :ident
def initialize(table, ident)
@table = table
@ident = ident
Database.sql "INSERT INTO #{@table} (id) VALUES (#{@ident})"
end
def set(col, val)
Database.sql "UPDATE #{@table} SET #{col}='#{val}' WHERE id=#{@ident}"
end
def get(col)
Database.sql("SELECT #{col} FROM #{@table} WHERE id=#{@ident}")[0][0]
end
end
Even if you do not write the above class
You can write code that defines accessor methods at runtime simply by inheriting ActiveRecord :: Base
.
--Rather than writing an accessor method for each attribute of the class, just inherit ActiveRecord :: Base
and write code that defines the accessor method at runtime (* write code that writes code * )be able to.
--The main task of class
is to take you into the context of the class.
--It's more like a scope operator than a class declaration.
--You can reopen existing classes, including standard classes, and modify them on the fly.
--Easy patches to classes, such as when you overwrite the original method of the same name, are called monkey patches.
--There is no connection between Ruby object classes and instance variables. --Instance variables only appear when a value is assigned. --The names and values of instance variables are like hash keys and values. --Both keys and values can vary from object to object. --Instance variables live in objects and methods live in classes.
--Even if it is the same method, it is called an instance method when focusing on a class, and it is called a method when focusing on an object.
--Class is an object --A class is an object, and the class of the class is the Class class. --The instance of the Class class is the class itself.
#Of the argument"false"Means "ignore inherited methods"
Class.instance_methods(false) # => [:allocate, :new, :superclass]
--The superclass of the Class class is Module --A class is a module that adds three instance methods (new, allocalte, superclass) for creating objects and inheriting classes.
Class.superclass # => Module
--Usually, select a module when including it somewhere, and select a class when creating or inheriting an instance.
--All capitalized references, including class and module names, are constants. --You can also change the value of the constant. --You can also change the value of the String class to break Ruby.
--Similarity between Ruby constants and files --All the constants in the program are arranged in a tree like a file system. --Modules and classes are directories and constants are files.
--Constant paths are separated by two colons. --When you are in the back of the constant tree, you can specify an external constant with an absolute path by starting with two colons indicating the root.
--Instance method Module # constants
--Returns all constants in the current scope. # => [: C,: Y]
--Something like the filesystem ls command.
--Class method Module.constants
--Returns the top-level constants of the current program.
--Class method Module.nesting
--Returns a constant containing the path. # => [M :: C :: M2, M :: C, M]
--A collection of instance variables with a link to a class. --Object methods live in the object's class, not the object, and are called class instance methods.
--An object (instance of Class class) with a list of instance methods and a link to the superclass.
--The Class class is a subclass of the Module class.
--The Class class has an instance method.
--Example: new
--Use the class name to refer to the class.
--Wrap the class in a namespace to avoid conflicts between class and module names. ――If you apply the monkey patch easily, you will get unexpected results.
load
--Used to load files and execute code. --Variables go out of scope when loading a file, but not out of scope. --Execute the file each time you call it.
require
--Used to import the library. --Read the file only once.
MyClass
class
=> Class
superclass
=> Object
Object
class
=> Class
Class
class
=> Class
superclass
=> Module
Module
superclass
=> Object
--Go up the inheritance chain until Ruby enters the receiver's class and finds a method. ―― "One step to the right, then up" rule --Go one step to the right towards the receiver class and go up the inheritance chain until you find a method.
MySubClass.ancestors # => [MySubclass, MyClass, Object, Kernel, BasicObject]
--The object to which the method to call belongs
--Example of class inheritance chain --Class → Superclass → Superclass ... (Continue to BasicObject)
--When you include a module in a class (or another module), Ruby inserts the module into the inheritance chain. ――It goes into ** directly above ** of the class to include.
module M1
def my_method
'My#my_method()'
end
end
class C
include M1
end
class D < C; end
D.ancestors # => [D, C, M, Object, Kernel, BasicObject]
--It works the same as include
, but the module is inserted under ** under ** of the include lower class.
--When the method is called, remembering the receiver reference will remind you who is the receiver when the method is executed.
--Ruby code is executed inside ** current object self **. --When calling a method, the receiver of the method becomes self. --From that point on, all instance variables become self instance variables. --All method calls that do not specify the receiver are calls to self. --If you explicitly call another object and call the method, that object becomes self this time.
--The state when the method is not called, or when all the called methods are returned.
self # => main
self.class # => Object
--Inside the definition of a class or module (outside the method), the role of self is the class or module itself.
class MyClass
self # => MyClass
end
--You cannot call a private method with an explicit receiver --The private method must be for the implicit receiver, self.
--Only you can call methods with private.
Refinements
--Similar to a monkey patch, but a way to prevent changes from reaching globally.
module StringExtensions
refine String do
def reverse
"esrever"
end
end
end
module StringStuff
using StringExtensions
"my_string".reverse # => "esrever"
end
"my_string".reverse # => "gnirts_ym"
--Refinations are only enabled in two places.
--Refinements are the same as open classes and monkey patches within a limited scope with Refinements enabled. --You can define new methods, redefine existing methods, and include and prepend modules. --Code with Refinements enabled takes precedence over the code in the refined class. --Refining a class is like pasting a patch into the original code.
-An object consists of multiple instance variables and links to classes.
-The object's methods live in the object's class (from the class's perspective, it's called an instance method).
-A class is an object of the Class class. Classmates are just constants.
-Class is a subclass of Module. A module is basically a collection of methods. In addition, classes can be instantiated with new or created hierarchically with superclass.
-The constants are arranged on a tree like a file system. Modules and classes are named directories, and regular constants are files.
-Each class has an inheritance chain that extends to BasicObject.
-When you call the method, Ruby goes one step to the right towards the receiver's class and then up the inheritance chain. It continues until you discover a method or end the inheritance chain.
-When you include a module in a class, the module is inserted directly above the inheritance chain for that class. Pre-penning a module inserts it directly under the inheritance chain for that class.
-When calling the method, the receiver becomes self.
-When defining a module (or class), that module becomes self.
-Instance variables are always considered instance variables of self.
-If you call a method without explicitly specifying a receiver, it is considered to be a self method.
-Refinements are like patching class code and overriding normal method search. However, Refinements are only valid in a limited area from the point where using is called to the point where the definition of the file or module ends.
-"Calling a method means sending a message to the object."
--Use dot notation or Object # send
to call the method.
obj = MyClass.new
obj.my_method(3) # => 6
obj.send(:my_method, 3) # => 6
--By using send
, the method name you want to call becomes a normal argument, and you can decide which method to call when the code is executed.
--Example of Pry # refresh
def refresh(options={})
defaults = {}
attributes = [ :input, :output, :commands, :print, :quiet,
:exception_handler, :hooks, :custom_completions,
:prompt, :memory_size, :extra_sticky_locals ]
attributes.each do |attribute|
defaults[attribute] = Pry.send attribute
end
# ...
defaults.merge!(options).each do |key, value|
# memory_size=The accessor of the attribute such as is called.
send("#{key}=", value) if respond_to?("#{key}=")
end
true
end
--Code example with dynamic dispatch added
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
def mouse
component :mouse
end
def cpu
component :cpu
end
def keyboard
component :keyboard
end
def component(name)
info = @data_source.send "get_#{name}_info", @id
price = @data_source.send "get_#{name}_price", @id
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
end
--Symbols are immutable (immutable), unlike the characters in strings, so they are suitable for names.
--A technique for defining methods at run time. --The method name can be determined at runtime.
Module#define_method
class MyClass
define_method :my_method do |my_arg|
my_arg * 3
end
end
obj = MyClass.new
obj.my_method(2) # => 6
--Code example with define_method added
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
def self.define_component(name)
define_method(name) do
info = @data_source.send "get_#{name}_info", @id
price = @data_source.send "get_#{name}_price", @id
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
end
define_component :mouse
define_component :cpu
define_component :keyboard
end
--Example of introspecting data_source and further refactoring
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
# Array#If you pass a block to grep, the block will be evaluated for all elements that match the regular expression.
#The string that matches the parentheses of the regular expression is a global variable$Stored in 1.
#Example: data_source is get_cpu_info and get_mouse_If you have two methods of info,
# Computer.define_You will call component twice (pass the strings "cpu" and "mouse" respectively)
data_source.methods.grep(/^get_(.*)_info$/) { Computer.define_component $1 }
end
def self.define_component(name)
define_method(name) do
# ...
end
end
end
method_missing
--When searching for a method, if the method is not found, call the method_missing
method to accept the loss.
--method_missing
is the private
instance method of BasicObject
inherited by all objects.
nick.send :method_missing, :my_method
# => NoMethodError: undefined method `my_method` for #<Lawyer:0x007f801b0f4978>
class Lawyer
def method_missing(method, *args)
puts "Called:#{method}(#{args.join(', ')})"
puts "(I also passed the block)" if block_given?
end
end
bob = Lawyer.new
bob.talk_simple('a', 'b') do
#block
end
# =>Called: talk_simple(a, b)
#(I also passed the block)
--The response of BasiObject # method_missing
will be NoMethodError.
--The place where unaddressed messages end up, and where NoMethodError is born.
--This is a message processed by method_missing, which looks like a normal call to the caller, but the corresponding method is not found on the receiver side.
--Hashie's example
module Hashie
class Mash < Hashie::Hash
def method_missing(method_name, *args, &blk)
#If the name of the called method is a hash key[]Call the method and return the corresponding value.
return self.[](method_name,&blk)ifkey?(method_name)
#The method name ends with "="If,"=To retrieve the name of the attribute, then retain its value.
#If neither matches, method_missing returns the default value.
match = method_name.to_s.match(/(.*?)([?=!]?)$/)
case match[2]
when "="
self[match[1]] = args.first
else
default(method_name, *args, &blk)
end
end
end
end
--A wrapped object that concentrates method calls on method_missing
, supplements the ghost method, and forwards it to another object.
--Example of Ghee (a library with easy access to HTTP API on GitHub)
class Ghee
class ResourceProxy
# ...
def method_missing(message, *args, &block)
# my_gist.Method calls like url, Hashee::Mash#method_Forward to missing.
subject.send(message, *args, &block)
end
def subject
#Receive a GitHub object in JSON and Hasie::Convert to Mash.
@subject ||= connection.get(path_prefix){|req| req.params.merge!params }.body
end
end
end
--Two points of Ghee
url
and description
.star
.url
to the wrapped hash.--Gee keeps the code simple with this two-step design.
--There is a ghost method when reading data, so there is no need to define a method.
--Define methods only when you need specific code like star
.
--Another advantage of these dynamic methods is that they can automatically respond to changes in the GitHub API. --Even if GitHub adds a new field, it's also a ghost method, so Ghee can support the call without modifying the source code.
--Computer class refactoring using method_missing
class Computer
def initialize(computer_id, data_source)
@id = computer_id
@data_source = data_source
end
# BasicObject#method_Override missing
def method_missing(name)
super if !@data_source.respond_to?("get_#{name}_info")
info = @data_source.send("get_#{name}_info", @id)
price = @data_source.send("get_#{name}_price", @id)
result = "#{name.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
end
#Respond to see if there is a ghost method_to_missing?Is properly overridden.
def respond_to_missing?(method, include_private = false)
@data_source.respond_to?("get_#{method}_info") || super
end
end
Module#const_missing
--A method that allows you to use old classmates without a new classmate namespace.
--Example when Task is renamed to Rake :: Task due to upgrade
class Module
def const_missing(const_name)
case const_name
when :Task
#Warn you about using obsolete class names.
Rake.application.const_warning(const_name)
Rake::Task
when :FileTask
Rake.application.const_warning(const_name)
Rake::FileTask
when :FileCreationTask
# ...
end
end
end
--The variable number
is defined in the block and is out of scope on the last line of method_missing
, and when the last line is executed, Ruby doesn't realize that number
is a variable and self
I think it's a method call without parentheses.
--Normally, NoMethodError is explicitly generated and the problem becomes clear, but here, since you have defined method_missing
yourself and called number
in it, the same event chain Occurs over and over again, eventually causing a stack overflow.
class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize
3.times do
number = rand(10) + 1
puts "#{number}..."
end
"#{person} got a #{number}"
end
end
--Do not introduce ghost methods when you don't need them. --Start by writing a regular method, make sure your code is working, and then refactor it to use method_missing.
--If the name of the ghost method (method defined by method_missing) conflicts with the name of the inherited real method, the latter wins. --A class in which inherited methods are deleted and there are only a minimum number of methods is called a blank slate.
--BasicObject, which is the root of Ruby's class hierarchy, has only the minimum necessary methods, and in order to quickly define a blank slate in Ruby, BasicObject should be inherited.
-The ghost method is the basic advice (always call super, always respond_to_missing?Redefines), which avoids most problems, but still causes complex bugs.
-The ghost method is not a real method, so it behaves differently than the actual method.
-There are some situations where only ghost methods can be used, such as when there are a large number of method calls or when the method to be called is known only at runtime.
-"Use dynamic methods if possible, ghost methods if you can't help"
--Block is a member of a large family of "callable objects". ――Brock's family has a different lineage from object-oriented programming, and follows the trend of "functional programming languages" such as LISP.
--Blocks can only be defined when calling a method.
--The block is passed to the method, which calls back the block using the yield keyword.
--When you call back a block, you can pass arguments just like a method.
--The block returns the result of evaluating the last line, just like a method.
--Inside the method, you can use the Kernel # block_given?
Method to check for blocks.
--In order to execute the code of the block, you need an environment such as local variables, instance variables, and self, and prepare for execution after putting them together. -** A block contains both code and a collection of bindings **.
--Define a block and get the binding at that point. --When you pass a block to a method, take that binding with you.
def my_method
#The bindings in the method are not visible to the block.
x = "Goodbye"
yield("cruel")
end
x = "Hello"
#Wrap a local binding like x and then pass the block to the method.
my_method = {|y| "#{x}, #{y} world"} # => "Hello, cruel world"
--Language such as Java and C # has a mechanism to refer to variables from "internal scope" to "external scope", but Ruby does not have such a nested structure of visibility, and scopes are properly distinguished. -** When entering the new scope (when the program changes scope), the old binding is replaced with the new binding **.
#Global variables can be accessed from any scope.
def a_scope
$var = "some value"
end
def another_scope
$var
end
a_scope
another_scope # => "some value"
#Top-level instance variables are instance variables of the main object at the top level.
#You can call it from anywhere the main becomes self.
#If the other object becomes self, the top-level instance variable goes out of scope.
@var = "Top level variables@var"
def my_method
@var
end
my_method # => "Top level variables@var"
class MyClass
def my_method
@var = "Top level variables@Not var!"
end
end
--There are three places where the program switches scopes and opens a new scope, and the keyword that marks each is called the scope gate.
--How to pass bindings across scope gates so that variables in other scopes are visible. ――This magic is also called ** nested lexical scope **. --The magic of pushing two scopes together and sharing variables is called ** flatscope **.
my_var = "success"
MyClass = Class.new do # class MyClass
puts "In the class definition#{my_var}!"
define_method :my_method do # def my_method
"Also in the method definition#{my_var}!"
end
end
--How to share variables while protecting them with scope gates.
def define_methods
shared = 0
Kernel.send :define_method, :counter do
shared
end
Kernel.send :define_method, :inc do |x|
shared += x
end
end
define_methods
counter # => 0
inc(4)
counter # => 4
-There are many bindings on Ruby scope.
-Scopes are separated by scope gates such as class, module, and def.
-Blocks (closures) can be used when you want to jump over a scope gate and sneak into a binding.
-By defining a block, you can wrap and carry the constraints in your current environment.
-Replace the scope gate with a method call, wrap the current binding in a closure, and pass that closure to the method.
-class is Class.new, module is Module.new and def are Modules.define_Can be replaced with method.
-This is the flat scope, the basic magic of closures.
-You can share bindings by defining multiple methods in the same flat scope and protecting them with scope gates.
-This is called a shared scope.
instance_eval
--BasicObject # instance_eval
** evaluates the block in the context of the object **.
-
--The block passed to instance_eval
is called a context searcher.
--Because it's code that explores the inside of an object and does something there.
class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
# instance_The block passed to eval is evaluated after making the receiver self, so
#Receiver private methods and@You can also access instance variables such as v.
obj.instance_eval do
self # => #<MyClass:0x3340dc @v=1>
@v # => 1
end
class C
def initialize
@x = 1
end
end
# instance_eval
class D
def twisted_method
@y = 2
# instance_When eval changes self to a receiver
#The instance variable of the caller (D) falls out of the block.
C.new.instance_eval { "@x: #{@x}, @y: #{@y}" }
end
end
D.new.twisted_method # => "@x: 1, @y: "
# instance_exec
class D
def twisted_method
@y = 2
#You can put C instance variables and D instance variables in the same scope.
C.new.instance_exec(@y) {|y| "#{@x}, @y: #{y}" }
end
end
D.mew.twisted_method # => "@x: 1, @y: 2"
--If you use the context searcher (block passed to instance_eval), you can break the encapsulation, so the use cases are limited in the following cases. --If you want to see the contents of the object from irb --For testing
--Padrino test example
describe "PadrinoLogger" do
context 'for logger functionality' do
context "static asset logging" do
...
should 'allow turning on static assets logging' do
Padrino.logger.instance_eval { @log_static = true }
# ...
get "/images/something.png "
assert_equal "Foo", body
assert_match /GET/, Padrino.logger.log.string
Padrino.logger.instance_eval { @log_static = false }
end
end
end
end
--Create an object just to evaluate the block. An environment for evaluating blocks.
--Callable object --In Ruby, "Save the code and call it later" method --In Proc. This is a block that has become an object. --In lambda. This is a variant of Proc. --In the method.
--In Ruby, almost everything is an object, but blocks are different.
Proc # call
.inc = Proc.new {|x| x + 1 }
inc.call(2) # => 3
--Two kernel methods to convert blocks to Proc - lambda - proc
dec = lambda {|x| x - 1 }
# dec = ->(x) { x - 1 }
dec.class # => Proc
dec.call(2) # => 1
--A block is like an anonymous argument passed to a method. --Case where yield is not enough. --When you want to pass a block to another method --When you want to convert a block to Proc
-** Assign bindings to blocks (give a "name" to point to the block) &
**
--Place at the end of the method argument sequence and put a &
mark in front of the name.
--Adding &
means that you want to receive the block passed to the method and convert it to Proc.
--Example of converting a block to Proc
def math(a, b)
yield(a, b)
end
# &After qualifying, it takes the block passed to the method and converts it to Proc!
def do_math(a, b, &operation)
math(a, b, &operation)
end
do_math(2, 3) {|x, y| x * y } # => 6
def my_method(&the_proc)
the_proc
end
p = my_method {|name| "Hello, #{name}!" }
p.class # => "Proc"
p.call("Bill") # => "Hello, Bill!"
--Example of returning Proc to a block
-** Convert Proc to Block &
**
def my_method(greeting)
"#{greeting}, #{yield}"
end
my_proc = proc { "Bill" }
my_method("Hello", &my_proc)
-Proc conversion by & is called "Proc coercion" (coercion: coercion, coercion, etc.). -It is very similar to * in multiple assignment in that it can be used on both the give side and the receive side of one operator, and it works exactly the opposite.
lambda
--Proc made with lambda is different from other Proc. --A Proc object created with lambda is called lambda. ――The other is simply called Proc. --You can check if Proc is lambda by using Proc # lambda? method.
--The difference between Proc and lambda
--The meaning of the return keyword is different between lambda and Proc.
#For lambda, return simply returns from lambda.
def double(callable_object)
callable_object.call * 2
end
1 = lambda { return 10 }
double(1) # => 20
#For Proc, return from the scope in which Proc is defined.
def another_double
p = Proc.new { return 10 }
result = p.call
return result * 2 #I won't come this far!
end
another_double # => 10
def double(callable_object)
callable_object.call * 2
end
p = Proc.new { return 10 }
double(p) # => LocalJumpError
p = Proc.new { 10 }
double(p) # => 20
--In general, lambda is stricter in handling arguments than Proc (or ordinary block) --If you call lambda with a different number of terms, you get an ArgumentError. --On the other hand, Proc matches the argument sequence to your expectations.
p = Proc.new
p.call(1, 2, 3) # => [1, 2]
p.call(1) # => [1, nil]
```
Proc vs lambda
--Generally speaking, lambda is said to be more intuitive than Proc because it's more like a method.
--Also, the number of terms is strict, and when you call return, it just ends.
--Many Rubyists choose lambda first, unless you need Proc functionality.
### Method object
--The method will also be a callable object like lambda.
```rb
class MyClass
def initialize(value)
@x = value
end
def my_method
@x
end
end
object = MyClass.new(1)
m = object.method :my_method #You can get the method itself as a Method object
m.call # => 1 # Object#The object obtained by method is Method#Can be executed using call
```
--`Method` can be converted to` Proc` with `Method # to_proc`, and blocks can be converted to methods with` define_method`.
--lambda is evaluated in the defined scope (closure), but Method is evaluated in the scope of the object to which it belongs.
UnboundMethod
--Something like a method separated from the original class or module.
```rb
module MyModule
def my_method
42
end
end
unbound = MyModule.instance_method(:my_method)
unbound.class # => UnboundMethod
```
### Summary of callable objects
```
-Block (not "object" but "callable"): evaluated in the defined scope
-Proc: An object of the Proc class. Like a block, it is evaluated in a defined scope.
-lambda: This is also a Proc class object, but it's slightly different from a normal Proc. Like blocks and procs, it is a closure and is evaluated within a defined scope.
-Method: Bind to the object and evaluate in the scope of the object. You can also pull it out of the scope of an object and bind it to another object.
-For methods and lambdas, return returns from the callable object.
-On the other hand, Proc and blocks return from the original context of the callable object.
-The method is strict with respect to the difference in the number of terms at the time of calling, and lambda is also almost strict.
-Proc and block are tolerant.
-The above difference is`Proc.new` 、 `Method#to_proc` 、 `&Qualification`And so on
You can convert from one callable object to another.
```
## Domain-specific language
- Example 1
```rb
def event(description)
puts "ALERT: #{description}" if yield
end
loda 'events.rb'
# events.rb
event 'Events that always occur' do
true
end
event 'Events that never occur' do
false
end
# => ALERT:Events that always occur
```
--Example 2
```rb
def setup(&block)
@setups << block
end
def event(description, &block)
@events << {:description => description, :condition => block }
end
@setups = []
@events = []
load 'events.rb'
@events.each do |event|
@setups.each do |setup|
setup.call
end
puts "ALERT: #{event[:description}" if event[:condition].call
end
```
### Delete global variables
--Example 2-Revised
```rb
lambda {
#setups and events are lambad local variables and are not visible to the outside world
setups = []
events = []
Kernel.send :define_method, :setup do |&block|
setups << block
end
Kernel.send :define_method, :event do |description, &block|
events << {:description => description, :condition => block}
end
Kernel.send :define_method, :each_setup do |&block|
setups.each do |setup|
block.call event
end
end
Kernel.send :define_method, :each_event do |&block|
events.each do |event|
block.call event
end
end
}.call
each_event do |event|
each_setup do |setup|
setup.call
end
puts "ALERT: #{event[:description]}" if event[:condition].call
end
#Alternatively, you can use a clean room in the context of the Object to prevent events from sharing instance variables.
each_event do |event|
env = Object.new
each_setup do |setup|
env.instance_eval &setup
end
puts "ALERT: #{event[:description]}" if env.instance_eval &(event[:condition])
end
```
## Chapter 4 Summary
```
-Scopegate and how does Ruby manage scopes?
-How to add flat and shared scopes to make bindings visible across scopes.
-In the scope of the object (instance_eval and instance_How to execute code (using exec) or how to execute code in a clean room.
-How to convert blocks and objects (Proc) to each other.
-How to convert methods and objects (Method and UnboundMethod) to each other.
-Types of callable objects (blocks, Proc, Lambda) and their differences. Difference from normal method.
-How to write your own small DSL.
```