Class: Respect::FakeNameProxy
- Inherits:
- BasicObject
- Defined in:
- lib/respect/fake_name_proxy.rb
Overview
The evaluation proxy used for the DSL.
This class sends all methods it receives to the target object it has received when initialized.
If the target's response to accept_name? is false, this proxy passes a nil value as first argument to target's dynamic methods and target's methods expecting a name as first argument.
This is useful to factor method code that should work in two different contexts. For instance, in the context of a hash schema definition, core statements expect a name as first argument whereas in the context of an array schema definition they do not.
HashSchema.define do |s|
s.integer "age", greater_than: 0
end
ArraySchema.define do |s|
# FakeNameProxy passes +nil+ here as value for the +name+ argument.
s.integer greater_than: 0
end
To factor this code, we define the integer method in a module included in both context classes.
module CoreStatements
def integer(name, = {})
update_context name, IntegerSchema.define()
end
end
class HashDef
include CoreStatements
def accept_name?; true; end
def update_context(name, schema)
@hash_schema[name] = schema
end
end
class ArrayDef
include CoreStatements
def accept_name?; false; end
def update_context(name, schema)
@array_schema.item = schema
end
end
The update_context method simply ignored the name argument in ArrayDef because it does not make any sens in this context.
Instance Attribute Summary (collapse)
-
- (Object) target
readonly
Return the DSL context object where the evaluation takes place.
Instance Method Summary (collapse)
-
- (Object) eval(&block)
Evaluate the given block in the context of this class and pass it this instance as argument and returns the value returned by the block.
-
- (FakeNameProxy) initialize(target)
constructor
A new instance of FakeNameProxy.
- - (Object) method_missing(symbol, *args, &block)
- - (Boolean) respond_to_missing?(symbol, include_all)
Constructor Details
- (FakeNameProxy) initialize(target)
A new instance of FakeNameProxy
51 52 53 |
# File 'lib/respect/fake_name_proxy.rb', line 51 def initialize(target) @target = target end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
- (Object) method_missing(symbol, *args, &block)
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/respect/fake_name_proxy.rb', line 58 def method_missing(symbol, *args, &block) if respond_to_missing?(symbol, false) # If the target's default behavior for its methods is to not accept a name as # first argument (this is the case for ArrayDef), we introspect the method # to decide whether we have to send a nil name as first argument. if should_fake_name? method = @target.method(symbol) else method = nil end # If we have a method and this method is either dynamic or expects a name as its first parameter. if method && (dynamic_method?(symbol) || has_name_param?(method)) args.insert(0, nil) begin method.call(*args, &block) rescue ::ArgumentError => e # Decrements argument number mentioned in the message by one. = e..sub(/ \((\d+) for (\d+)\)$/) do |match| # FIXME(Nicolas Despres): Not sure if this class is still # re-entrant since we use $1 and $2. I could not find a way to access # to the data matched by sub. " (#{$1.to_i - 1} for #{$2.to_i - 1})" end ::Kernel.raise(::ArgumentError, ) end else @target.public_send(symbol, *args, &block) end else super end end |
Instance Attribute Details
- (Object) target (readonly)
Return the DSL context object where the evaluation takes place.
56 57 58 |
# File 'lib/respect/fake_name_proxy.rb', line 56 def target @target end |
Instance Method Details
- (Object) eval(&block)
Evaluate the given block in the context of this class and pass it this instance as argument and returns the value returned by the block.
98 99 100 |
# File 'lib/respect/fake_name_proxy.rb', line 98 def eval(&block) block.call(self) end |
- (Boolean) respond_to_missing?(symbol, include_all)
91 92 93 94 |
# File 'lib/respect/fake_name_proxy.rb', line 91 def respond_to_missing?(symbol, include_all) # We ignore include_all since we are only interested in non-private methods. @target.respond_to?(symbol) end |