Class: Constraint::Shell

Inherits:
Object
  • Object
show all
Extended by:
Helper
Includes:
Helper
Defined in:
lib/constraint.rb

Overview

If CONSTRAINT_DISABLE is set to true before loading this library, constraint checking is turned off.

Direct Known Subclasses

CArray

Instance Attribute Summary collapse

Attributes included from Helper

#constraints, #descriptions

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helper

and_constraint, handle_constraint_violation, log_constraint_exception, or_constraint

Constructor Details

#initialize(core = nil, predecessor = nil) ⇒ Shell

Returns a new instance of Shell.



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/constraint.rb', line 218

def initialize(core=nil, predecessor=nil)
    if predecessor
        @descriptions = predecessor.descriptions
        @constraints  = predecessor.constraints
    else
        @descriptions = self.class.descriptions.dup
        @constraints  = self.class.constraints
        @constraints  = @constraints.dup if @constraints
    end
    
    if core
        @constrained_value = core
    else
        @constrained_value = new_constrained
    end

    unless CONSTRAINT_DISABLE
        process_constrained_value {|e| check_constraints(e)}
    end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Delegate unknown methods to @constrained_value and filter the return value through #check_constraints.

See also the notes on #with_constraints and Shell.with_arguments_constrained.



313
314
315
# File 'lib/constraint.rb', line 313

def method_missing(method, *args, &block)
    with_constraints(@constrained_value.send(method, *args, &block))
end

Instance Attribute Details

#constrained_valueObject (readonly)

The actual value that is covered by the Shell.



150
151
152
# File 'lib/constraint.rb', line 150

def constrained_value
  @constrained_value
end

Class Method Details

.inherited(subclass) ⇒ Object



158
159
160
161
162
163
# File 'lib/constraint.rb', line 158

def inherited(subclass)
    parent = self
    subclass.class_eval do
        inherit_constraint(parent)
    end
end

.with_all_arguments_constrained(*methods) ⇒ Object

Wrap methods so that all arguments are filtered through #check_constraints.

methods

Method names as symbols



168
169
170
171
172
# File 'lib/constraint.rb', line 168

def with_all_arguments_constrained(*methods)
    with_arguments_constrained(*methods) do |checker, *args| 
        args.collect {|e| checker.call(e)}
    end
end

.with_arguments_constrained(*methods, &block) ⇒ Object

Wrap methods so that some arguments are filtered through #check_constraints. This is useful in two situations:

* if filtering the return value would be inefficient -- 
e.g. with methods performing trivial Array operations 
where the return value will comply with the constraints 
if its argument do.

* if the return value of the method call is not an 
instance of the actual value's class (only then will the 
value's integrity be checked)

See also the notes on Shell#with_constraints.

methods

Method names as symbols

block

Select the arguments that should be filtered



191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/constraint.rb', line 191

def with_arguments_constrained(*methods, &block)
    unless CONSTRAINT_DISABLE
        methods.each do |method|
            define_method(method) do |*args|
                unless args.empty?
                    checker = lambda {|a| check_constraints(a)}
                    args    = block.call(checker, *args)
                end
                with_constraints(@constrained_value.send(method, *args))
            end
        end
    end
end

.without_constraints(*methods) ⇒ Object

Delegate methods to @constrained_value without taking any measures.



207
208
209
210
211
212
213
# File 'lib/constraint.rb', line 207

def without_constraints(*methods)
    methods.each do |method|
        define_method(method) do |*args|
            with_constraints(@constrained_value.send(method, *args))
        end
    end
end

Instance Method Details

#check_constraints(object) ⇒ Object

Check if object complies with @constraints.



267
268
269
# File 'lib/constraint.rb', line 267

def check_constraints(object)
    object
end

#cloneObject



243
244
245
# File 'lib/constraint.rb', line 243

def clone
    replicate_constraint_shell(super)
end

#dupObject



239
240
241
# File 'lib/constraint.rb', line 239

def dup
    replicate_constraint_shell(super)
end

#new_constrainedObject

Construct a new instance.



248
249
250
251
# File 'lib/constraint.rb', line 248

def new_constrained
    # nil
    raise 'Subclass responsibility'
end

#process_constrained_valueObject

Filters @constrained_value through the supplied block (usually a call to #check_constraints) and collects the output in @constrained_value).

block

The filter



257
258
259
# File 'lib/constraint.rb', line 257

def process_constrained_value
    @constrained_value = yield @constrained_value
end

#respond_to?(*args) ⇒ Boolean

Forward to @constrained_value.

Returns:

  • (Boolean)


322
323
324
# File 'lib/constraint.rb', line 322

def respond_to?(*args)
    super or @constrained_value.respond_to?(*args)
end

#with_constraints(new_value) ⇒ Object

Maintain object identity according to the return value of block. This method can be used when overwriting specific methods and if you don’t want to use the provided wrapper methods (e.g., Shell.with_arguments_constrained).

If the return value is of the same kind as @constrained_value and if block can’t be trusted, then the return value is filtered through #check_constraints.

In order to filter the arguments of methods that don’t return an object of the same kind as @constrained_value, you have to define an explicit delegator using Shell.with_arguments_constrained and friends.

new_value

The result from the method call

[block]

Optional, called @constrained_value is new_value



292
293
294
295
296
297
298
299
300
301
# File 'lib/constraint.rb', line 292

def with_constraints(new_value)
    if new_value.equal?(@constrained_value)
        yield if block_given?
        return self
    elsif new_value.instance_of?(@constrained_value.class)
        return self.class.new(new_value, self)
    else
        return new_value
    end
end