class DSeL::API::Generator

Attributes

last_call[R]

@return [Hash]

Data on the last call made.

Public Class Methods

new() click to toggle source

@private

# File lib/dsel/api/generator.rb, line 53
def initialize
    reset
end

Private Class Methods

method_missing( sym, *args, &block ) click to toggle source
Calls superclass method
# File lib/dsel/api/generator.rb, line 264
def method_missing( sym, *args, &block )
    if instance.respond_to?( sym )
        instance.send( sym, *args, &block )
    else
        super( sym, *args, &block )
    end
end
respond_to?( *args ) click to toggle source
Calls superclass method
# File lib/dsel/api/generator.rb, line 272
def respond_to?( *args )
    super || instance.respond_to?( *args )
end

Public Instance Methods

call_handler_catch_all_name( type ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 152
def call_handler_catch_all_name( type )
    "_#{type}_catch_all_#{token}".to_sym
end
call_handler_name( type, *possible_object ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 140
def call_handler_name( type, *possible_object )
    possible_object.empty? ?
        call_handler_catch_all_name( type ) :
        call_handler_with_object_name( type, possible_object.first )
end
call_handler_with_object_name( type, object ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 147
def call_handler_with_object_name( type, object )
    "_#{type}_#{call_object_hash_for( object )}_#{token}".to_sym
end
call_object_hasher=( hasher ) click to toggle source

@note Defaults to ‘Object#hash` and assumes case-insensitive strings.

Sets a way to calculate unique routing hashes for call objects.

@param [Symbol, call] hasher

* `Symbol`: Object method.
* `#call`: To be passed each object and return an Integer hash.
# File lib/dsel/api/generator.rb, line 43
def call_object_hasher=( hasher )
    if hasher && !(hasher.is_a?( Symbol ) || hasher.respond_to?( :call ))
        fail ArgumentError,
             "Expected Symbol or #call-able hasher, got: #{hasher.inspect}"
    end

    @call_object_hasher = hasher
end
calling( node, type, handler, args, *possible_object, &block ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 101
def calling( node, type, handler, args, *possible_object, &block )
    synchronize do
        @last_call = {
            node: node,
            type: type
        }

        if !possible_object.empty?
            @last_call.merge!( object: possible_object.first )
        end

        @last_call.merge!(
            handler: handler,
            args:    args
        )

        if last_call_with_caller?
            @last_call[:caller] = caller
        end
    end

    t = Time.now
    r = block.call
    spent = Time.now - t

    synchronize do
        @last_call[:time] = spent
        call_on_call( @last_call )
    end

    r
end
define_call_handler( node, type, *possible_object, &block ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 80
def define_call_handler( node, type, *possible_object, &block )
    node.instance_eval do
        handler = Generator.call_handler_name( type, *possible_object )

        if method_defined?( handler )
            fail ArgumentError,
                 'Call handler already exists: ' <<
                     Generator.handler_to_s( self, type, *possible_object )
        end

        # We can get the options from here and do stuff...I don't know.
        push_call_handler( type, handler, *possible_object )
        define_method handler, &block
    end

    define_call_router( node, type )

    nil
end
define_definers( node, *types ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 69
def define_definers( node, *types )
    synchronize do
        types.each do |type|
            define_definer( node, type )
        end
    end

    nil
end
definer_name( type ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 135
def definer_name( type )
    "def_#{type}".to_sym
end
handler_to_s( node, type, *possible_object ) click to toggle source

@private

# File lib/dsel/api/generator.rb, line 157
def handler_to_s( node, type, *possible_object )
    r = "#{node} #{type}"

    if !possible_object.empty?
        object = possible_object.first
        r << ' '
        r << (object.nil? ? 'nil' : object.to_s)
    end

    r
end
last_call_with_caller!() click to toggle source
# File lib/dsel/api/generator.rb, line 22
def last_call_with_caller!
    @last_call_with_caller = true
end
last_call_with_caller?() click to toggle source
# File lib/dsel/api/generator.rb, line 14
def last_call_with_caller?
    @last_call_with_caller
end
last_call_without_caller!() click to toggle source
# File lib/dsel/api/generator.rb, line 18
def last_call_without_caller!
    @last_call_with_caller = false
end
on_call( &block ) click to toggle source
# File lib/dsel/api/generator.rb, line 26
def on_call( &block )
    fail ArgumentError, 'Missing &block' if !block

    synchronize do
        @on_call << block
    end

    self
end
reset() click to toggle source

@private

# File lib/dsel/api/generator.rb, line 58
def reset
    @mutex   = Monitor.new
    @on_call = []

    @last_call_with_caller = false
    @call_object_hasher    = false

    self
end

Private Instance Methods

call_object_hash_for( object ) click to toggle source
# File lib/dsel/api/generator.rb, line 177
def call_object_hash_for( object )
    if !@call_object_hasher
        default_call_object_hash_for( object )
    elsif @call_object_hasher.is_a?( Symbol )
        object.send( @call_object_hasher )
    else
        @call_object_hasher.call( object )
    end.tap do |h|
        next if h.is_a? Integer

        fail ArgumentError,
             "Hasher #{@call_object_hasher.inspect} returned non-Integer" <<
             " hash #{h.inspect} for object #{object.inspect}."
    end
end
call_on_call( *args ) click to toggle source
# File lib/dsel/api/generator.rb, line 171
def call_on_call( *args )
    @on_call.each do |b|
        b.call *args
    end
end
default_call_object_hash_for( object ) click to toggle source
# File lib/dsel/api/generator.rb, line 193
def default_call_object_hash_for( object )
    object = object.downcase if object.is_a?( String )
    object.hash
end
define_call_router( node, type ) click to toggle source
# File lib/dsel/api/generator.rb, line 218
def define_call_router( node, type )
    node.instance_eval do
        return if method_defined?( type )

        # Basically a router, object-based and catch-all.
        define_method type do |*args, &block|
            if !args.empty?
                object      = args.shift
                with_object = Generator.call_handler_with_object_name( __method__, object )

                if respond_to?( with_object )
                    r = nil
                    Generator.calling( self.class, type, with_object, args, object ) do
                        r = send( with_object, *args, &block )
                    end

                    return r.nil? ? self : (r == :nil ? nil :r)
                end

                args.unshift object
            end

            catch_all = Generator.call_handler_catch_all_name( __method__ )
            if respond_to?( catch_all )

                r = nil
                Generator.calling( self.class, type, catch_all, args ) do
                    r = send( catch_all, *args, &block )
                end

                return r.nil? ? self : r
            end

            fail NoMethodError,
                 "No handler for: #{Generator.handler_to_s( self.class, type, *args )}"
        end
    end
    nil
end
define_definer( node, type ) click to toggle source
# File lib/dsel/api/generator.rb, line 202
def define_definer( node, type )
    definer = Generator.definer_name( type )

    # We can get the options from here and do stuff...I don't know.
    node.push_definer( type, definer )

    node.class_eval( "undef :#{definer} if defined? #{definer}" )
    node.define_singleton_method definer do |*possible_object, &block|
        if possible_object.size > 1
            fail ArgumentError,  'No more than 1 objects are allowed.'
        end

        Generator.define_call_handler( self, type, *possible_object, &block )
    end
end
synchronize( &block ) click to toggle source
# File lib/dsel/api/generator.rb, line 258
def synchronize( &block )
    @mutex.synchronize( &block )
end
token() click to toggle source
# File lib/dsel/api/generator.rb, line 198
def token
    @token ||= SecureRandom.hex
end