Class: Alf::Algebra::Signature

Inherits:
Object
  • Object
show all
Defined in:
lib/alf/algebra/support/signature.rb

Overview

Provides an operator signature

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(operator) {|_self| ... } ⇒ Signature

Creates an empty signature instance

Parameters:

  • the (Class)

    operator class to which this signature belongs

Yields:

  • (_self)

Yield Parameters:


18
19
20
21
22
23
# File 'lib/alf/algebra/support/signature.rb', line 18

def initialize(operator)
  @operator = operator
  @arguments = []
  @options = []
  yield(self) if block_given?
end

Instance Attribute Details

#argumentsArray (readonly)

Returns signature arguments

Returns:

  • (Array)

    signature arguments


10
11
12
# File 'lib/alf/algebra/support/signature.rb', line 10

def arguments
  @arguments
end

#operatorClass (readonly)

Returns the operator class to which this signature belongs

Returns:

  • (Class)

    the operator class to which this signature belongs


7
8
9
# File 'lib/alf/algebra/support/signature.rb', line 7

def operator
  @operator
end

#optionsArray (readonly)

Returns signature options

Returns:

  • (Array)

    signature options


13
14
15
# File 'lib/alf/algebra/support/signature.rb', line 13

def options
  @options
end

Instance Method Details

#argument(name, domain, default = nil, descr = nil) ⇒ Object

Adds an argument to the signature

Parameters:

  • name (Symbol)

    argument name

  • domain (Class)

    argument domain

  • default (Object) (defaults to: nil)

    (optional) default value


30
31
32
# File 'lib/alf/algebra/support/signature.rb', line 30

def argument(name, domain, default = nil, descr = nil)
  arguments << [name, domain, default, descr]
end

#collect_on(op) ⇒ Array

Collects signature values on a given operator.

This methods returns a triple `[datasets, arguments, options]` with the respective values collected on `op`.

Parameters:

  • op (Operator)

    an operator, which should be an instance of `self.operator`

Returns:

  • (Array)

    a triple [datasets, arguments, options] with operands, then signature values


128
129
130
131
132
133
134
135
136
# File 'lib/alf/algebra/support/signature.rb', line 128

def collect_on(op)
  oper = op.operands
  args = arguments.map{|name,_| op.send(name) }
  opts = Hash[options.map{|name,dom,defa,_|
    val = op.send(name)
    (val == defa) ? nil : [name, val]
  }.compact]
  [oper, args, opts]
end

#installHash

Installs the signature on the operator class

This method installs an attr reader and an attr writer for each signature argument and each signature option.

Returns:

  • (Hash)

    the default options to use


69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/alf/algebra/support/signature.rb', line 69

def install
  clazz = operator
  code = (arguments + options).each{|siginfo|
    name, domain, = siginfo
    clazz.send(:attr_reader, name)
    clazz.send(:define_method, :"#{name}=") do |val|
      instance_variable_set(:"@#{name}", Support.coerce(val, domain))
    end
    clazz.send(:private, :"#{name}=")
  }
  default_options
end

#option(name, domain, default = nil, descr = nil) ⇒ Object

Adds an option to the signature

Parameters:

  • name (Symbol)

    argument name

  • domain (Class)

    argument domain

  • default (Object) (defaults to: nil)

    (optional) default value


39
40
41
# File 'lib/alf/algebra/support/signature.rb', line 39

def option(name, domain, default = nil, descr = nil)
  options << [name, domain, default, descr]
end

#option_parser(receiver, opt = OptionParser.new) ⇒ OptionParser

Builds an option parser instance `opt` prepared for installing options on `receiver`.

Parameters:

  • a (Hash|Operator)

    receiver for option values

  • opt (OptionParser) (defaults to: OptionParser.new)

    the parser to fill with options

Returns:

  • (OptionParser)

    `opt`


49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/alf/algebra/support/signature.rb', line 49

def option_parser(receiver, opt = OptionParser.new)
  options.each do |option|
    name, dom, defa, descr = option
    opt.on(option_name(option), descr || "") do |val|
      if receiver.is_a?(Hash)
        receiver[name] = val
      else
        receiver.send(:"#{name}=", val)
      end
    end
  end
  opt
end

#parse_args(args, receiver) ⇒ Operator

Parses arguments `args` passed to the operator `initialize` and sets attributes accordingly on `receiver`.

Parameters:

  • args (Array)

    an array of initialize arguments

  • receiver (Operator)

    an operator instance

Returns:


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/alf/algebra/support/signature.rb', line 88

def parse_args(args, receiver)

  # 1) Check and set operands, passed as an array as first argument
  invalid_args!(args) unless args.first.is_a?(Array)
  receiver.send(:operands=, args.shift.map{|op| Operand.coerce(op)})

  # 2) Extract options if provided
  optargs = default_options
  if args.size == (1+arguments.size)
    # options are passed as last argument
    invalid_args!(args) unless args.last.is_a?(Hash)
    optargs = optargs.merge(args.pop)
  elsif args.size > arguments.size
    # too many arguments here
    invalid_args!(args)
  end

  # 3) Set options now, including default ones
  optargs.each_pair do |name,val|
    receiver.send(:"#{name}=", val)
  end

  # 4) Parse other arguments now
  with_each_arg(args) do |name,dom,value|
    invalid_args!(args) if value.nil?
    receiver.send(:"#{name}=", value)
  end

  receiver
end

#to_lispyObject

Returns a lispy synopsis for this signature

Example:

Alf::Algebra::Project.signature.to_shell
# => "(project operand, attributes:AttrList, {allbut: Boolean})"

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/alf/algebra/support/signature.rb', line 144

def to_lispy
  cmd  = operator.rubycase_name
  oper = operator.nullary? ? "" : (operator.unary? ? "operand" : "left, right")

  args = arguments.map{|name,dom,_|
    dom = dom.to_s[/::([A-Za-z]+)$/, 1] || dom.to_s
    "#{name}:#{dom}"
  }.join(", ")
  args = (args.empty? ? "#{oper}" : "#{oper}, #{args}").strip

  opts = options.map{|name,dom,_|
    dom = dom.to_s[/::([A-Za-z]+)$/, 1] || dom.to_s
    "#{name}: #{dom}"
  }.join(', ')
  opts = opts.empty? ? "" : "{#{opts}}"

  argopt = [args, opts].select{|s| !s.empty?}.join(', ')
  "#{cmd}(#{argopt}".strip + ")"
end