class Rack::RPC::Operation

Represents an RPC server operation.

Attributes

context[R]

@return [Object]

Public Class Methods

arity() click to toggle source

Returns the arity range for this operation class.

@return [Range]

# File lib/rack/rpc/operation.rb, line 79
def self.arity
  @arity ||= begin
    if const_defined?(:ARITY)
      const_get(:ARITY)
    else
      min, max = 0, 0
      operands.each do |name, options|
        min += 1 unless options[:optional].eql?(true)
        max += 1
      end
      Range.new(min, max)
    end
  end
end
execute(&block) click to toggle source

Defines the `#execute` instance method.

@yield @return [void]

# File lib/rack/rpc/operation.rb, line 53
def self.execute(&block)
  self.send(:define_method, :execute) do
    begin
      before_execute if respond_to?(:before_execute)
      result = instance_eval(&block)
      after_execute if respond_to?(:after_execute)
      result
    rescue Exception => error
      after_error(error) if respond_to?(:after_error)
      raise
    end
  end
end
new(args = []) click to toggle source

Initializes a new operation with the given arguments.

@param [Hash{Symbol => Object}] args

# File lib/rack/rpc/operation.rb, line 103
def initialize(args = [])
  case args
    when Array then initialize_from_array(args)
    when Hash  then initialize_from_hash(args)
    else case
      when args.respond_to?(:to_args)
        initialize_from_array(args.to_args)
        @__context__ = args.context if args.respond_to?(:context)
      else raise ArgumentError, "expected an Array or Hash, but got #{args.inspect}"
    end
  end

  initialize! if respond_to?(:initialize!)
end
operand(name, type = Object, options = {}) click to toggle source

Defines an operand for this operation class.

@example

class Multiply < Operation
  operand :x, Numeric
  operand :y, Numeric
end

@param [Symbol, to_sym] name @param [Class] type @param [Hash{Symbol => Object}] options @option options [Boolean] :optional (false) @option options [Boolean] :nullable (false) @return [void]

# File lib/rack/rpc/operation.rb, line 21
def self.operand(name, type = Object, options = {})
  raise TypeError, "expected a Class, but got #{type.inspect}" unless type.is_a?(Class)
  operands[name.to_sym] = options.merge(:type => type)
end
operands() click to toggle source

Returns the operand definitions for this operation class.

@return [Hash{Symbol => Hash}]

# File lib/rack/rpc/operation.rb, line 71
def self.operands
  @operands ||= {}
end
prepare(&block) click to toggle source

Defines the `#prepare` instance method.

@yield @return [void]

# File lib/rack/rpc/operation.rb, line 31
def self.prepare(&block)
  self.send(:define_method, :prepare) do
    begin
      begin
        before_prepare if respond_to?(:before_prepare)
        instance_eval(&block)
      ensure
        after_prepare if respond_to?(:after_prepare)
      end
      self
    rescue Exception => error
      after_error(error) if respond_to?(:after_error)
      raise
    end
  end
end

Public Instance Methods

execute() click to toggle source

Executes this operation.

@abstract @return [void]

# File lib/rack/rpc/operation.rb, line 192
def execute
  raise NotImplementedError, "#{self.class}#execute"
end
prepare() click to toggle source

Prepares this operation.

@abstract @return [void] `self`

# File lib/rack/rpc/operation.rb, line 183
def prepare
  self
end
to_a() click to toggle source

Returns the array representation of the arguments to this operation.

@return [Array]

# File lib/rack/rpc/operation.rb, line 200
def to_a
  self.class.operands.inject([]) do |result, (param_name, param_options)|
    result << instance_variable_get("@#{param_name}")
    result
  end
end
to_hash() click to toggle source

Returns the hash representation of the arguments to this operation.

@return [Hash]

# File lib/rack/rpc/operation.rb, line 211
def to_hash
  self.class.operands.inject({}) do |result, (param_name, param_options)|
    result[param_name] = instance_variable_get("@#{param_name}")
    result
  end
end
to_json() click to toggle source

Returns the JSON representation of the arguments to this operation.

@return [String] a serialized JSON object

# File lib/rack/rpc/operation.rb, line 222
def to_json
  to_hash.to_json
end

Protected Instance Methods

initialize_from_array(args) click to toggle source

@private

# File lib/rack/rpc/operation.rb, line 120
def initialize_from_array(args)
  validate_arity!(args)

  pos = 0
  self.class.operands.each do |param_name, param_options|
    arg = args[pos]; pos += 1

    validate_argument!(arg, param_name, param_options)

    instance_variable_set("@#{param_name}", arg)
  end
end
initialize_from_hash(args) click to toggle source

@private

# File lib/rack/rpc/operation.rb, line 136
def initialize_from_hash(args)
  validate_arity!(args)

  params = self.class.operands
  args.each do |param_name, arg|
    param_options = params[param_name.to_sym]

    raise ArgumentError, "unknown parameter name #{param_name.inspect}" unless param_options
    validate_argument!(arg, param_name, param_options)

    instance_variable_set("@#{param_name}", arg)
  end
end
validate_argument!(arg, param_name, param_options) click to toggle source

@private

# File lib/rack/rpc/operation.rb, line 164
def validate_argument!(arg, param_name, param_options)
  return if arg.nil? && (param_options[:nullable] || param_options[:optional])

  if (param_type = param_options[:type]) && !(param_type === arg)
    case param_type
      when Regexp
        raise TypeError, "expected a String matching #{param_type.inspect}, but got #{arg.inspect}"
      else
        raise TypeError, "expected a #{param_type}, but got #{arg.inspect}"
    end
  end
end
validate_arity!(args) click to toggle source

@private

# File lib/rack/rpc/operation.rb, line 153
def validate_arity!(args)
  unless self.class.arity.include?(argc = args.count)
    raise ArgumentError, (argc < self.class.arity.min) ?
      "too few arguments (#{argc} for #{self.class.arity.min})" :
      "too many arguments (#{argc} for #{self.class.arity.max})"
  end
end