Module: Such::Thing

Defined in:
lib/such/thing.rb

Constant Summary collapse

SIGNALS =
['clicked']
INTOS =
[:set_submenu, :pack_start, :append, :add]
PARAMETERS =
lambda{@@PARAMETERS[_1]}
@@PARAMETERS =

PARAMETERS’ pretense of being a Hash constant :P

{}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.configure(conf) ⇒ Object



10
11
12
# File 'lib/such/thing.rb', line 10

def self.configure(conf)
  @@PARAMETERS = conf
end

.do_config(obj, *parameters, &block) ⇒ Object

Given an Object not sub-classed as a Thing:

obj = NotAThing.new

One can still act on it like a Thing as follows:

Thing.do_config(obj, *parameters, &block)


128
129
130
131
132
133
# File 'lib/such/thing.rb', line 128

def self.do_config(obj, *parameters, &block)
  container, arguments, methods, signals = Thing.do_parameters(parameters)
  Thing.do_methods(obj, methods, container)
  Thing.do_links(obj, signals, block)
  warn "Warning: arguments not used in do_config(#{obj.class}...)." if arguments.length > 0
end


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/such/thing.rb', line 106

def self.do_links(obj, signals, block)
  return if signals.first==''
  if block
    signals=SIGNALS if signals.empty?
    signals.each do |signal|
      break if signal==''
      begin
        obj.signal_connect(signal){|*emits| block.call(*emits, signal)}
        Thing.trace_signal(obj, signal) if $VERBOSE
      rescue GLib::NoSignalError
        warn "Warning: no #{signal} signal for #{obj.class}"
      end
    end
  elsif !signals.empty?
    warn "Warning: No block given for #{signals.join(',')} on #{obj.class}."
  end
end

.do_method(obj, mthd, *args) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/such/thing.rb', line 85

def self.do_method(obj, mthd, *args)
  Thing.trace_method(obj, mthd, args) if $VERBOSE
  m = obj.method(mthd)
  begin
    m.call(*args)
  rescue ArgumentError, TypeError
    # Assume user meant to iterate. Note that the heuristic is not perfect.
    $stderr.puts "# Iterated Method #{mthd}." if $VERBOSE
    [*args].each{m.call(*_1)}
  end
end

.do_methods(obj, methods, container = nil) ⇒ Object



97
98
99
100
101
102
103
104
# File 'lib/such/thing.rb', line 97

def self.do_methods(obj, methods, container=nil)
  # If user does not specify how to add to container, assume default way.
  methods[:into]=Thing.which_method(container) if container and not methods.has_key?(:into)
  methods.each do |mthd, args|
    (mthd==:into)? Thing.into(obj, container, *args) :
                   Thing.do_method(obj, mthd, *args)
  end
end

.do_parameters(parameters) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/such/thing.rb', line 37

def self.do_parameters(parameters)
  container, arguments, methods, signals = nil, [], {}, []
  while parameter = parameters.shift
    case parameter
    when Symbol
      # Symbols are expected to translate to something else.
      Thing.do_symbol parameter, parameters
    when Array
      # Arrays are added to the Thing's arguments list.
      arguments.concat parameter
    when Hash
      # Hashes are expected to be a symbol list of methods on Thing with respective arguments.
      # It's possible to override a previously defined method with new arguments.
      methods.merge! parameter
    when String
      # Typically a signal: Thing#signal_connect(signal){|*emits| block.call(*emits)}
      signals.push parameter
    else
      # Assume it's a container
      container = parameter
    end
  end
  signals.uniq!
  return container, arguments, methods, signals
end

.do_symbol(parameter, parameters) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/such/thing.rb', line 22

def self.do_symbol(parameter, parameters)
  if @@PARAMETERS.has_key?(parameter)
    p = @@PARAMETERS[parameter]
    (parameter[-1]=='!')? parameters.unshift(*p) : parameters.unshift(p)
  else
    if parameter[-1]=='!'
      p = parameter[0..-2]
      parameters.unshift(p.downcase.to_sym)
      parameters.unshift(p.upcase.to_sym)
    else
      warn "Warning: Such::Thing::PARAMETERS[#{parameter}] not defined"
    end
  end
end

.into(obj, container = nil, mthd = nil, *args) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/such/thing.rb', line 69

def self.into(obj, container=nil, mthd=nil, *args)
  if container
    if mthd
      unless container.respond_to?(mthd)
        raise "Need container & method. Got #{container.class}##{mthd}(#{obj.class}...)"
      end
    else
      mthd=Thing.which_method(container)
    end
    Thing.trace_method(container, mthd, [obj.class,*args]) if $VERBOSE
    container.public_send(mthd, obj, *args)
  else
    warn "Warning: Container for #{self.class} not given."
  end
end

.trace_method(obj, mthd, args) ⇒ Object



14
15
16
# File 'lib/such/thing.rb', line 14

def self.trace_method(obj, mthd, args)
  $stderr.puts "#{obj.class}##{mthd}(#{[*args].join(',')})"
end

.trace_signal(obj, signal) ⇒ Object



18
19
20
# File 'lib/such/thing.rb', line 18

def self.trace_signal(obj, signal)
  $stderr.puts "#{obj.class} links #{signal}"
end

.which_method(container, methods = INTOS) ⇒ Object



63
64
65
66
67
# File 'lib/such/thing.rb', line 63

def self.which_method(container, methods=INTOS)
  mthd = methods.detect{container.respond_to?_1}
  raise "Don't know how to put into #{container.class}." if mthd.nil?
  return mthd
end

Instance Method Details

#initialize(*parameters, &block) ⇒ Object

The alternate sub-class constructor:



136
137
138
139
140
141
# File 'lib/such/thing.rb', line 136

def initialize(*parameters, &block)
  container, arguments, methods, signals = Thing.do_parameters(parameters)
  super(*arguments)
  Thing.do_methods(self, methods, container)
  Thing.do_links(self, signals, block)
end