Class: Module

Inherits:
Object
  • Object
show all
Defined in:
lib/bud/monkeypatch.rb

Instance Method Summary collapse

Instance Method Details

#bloom(block_name = nil, &block) ⇒ Object

bloom statements to be registered with Bud runtime. optional block_name assigns a name for the block; this is useful documentation, and also allows the block to be overridden in a child class.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/bud/monkeypatch.rb', line 170

def bloom(block_name=nil, &block)
  # If no block name was specified, generate a unique name
  if block_name.nil?
    @block_id ||= 0
    block_name = "#{Module.get_class_name(self)}__#{@block_id}".to_sym
    @block_id += 1
  else
    unless block_name.class <= Symbol
      raise Bud::CompileError, "block name must be a symbol: #{block_name}"
    end
  end

  # Note that we don't encode the module name ("self") into the name of the
  # method. This allows named blocks to be overridden (via inheritance or
  # mixin) in the same way as normal Ruby methods.
  meth_name = "__bloom__#{block_name}"

  # Don't allow duplicate named bloom blocks to be defined within a single
  # module; this indicates a likely programmer error.
  if instance_methods(false).include?(meth_name) ||
     instance_methods(false).include?(meth_name.to_sym)
    raise Bud::CompileError, "duplicate block name: '#{block_name}' in #{self}"
  end
  ast = Source.read_block(caller[0]) # pass in caller's location via backtrace

  # ast corresponds only to the statements of the block. Wrap it in a method
  # definition for backward compatibility for now.

  # If the block contained multiple statements, the AST will have a top-level
  # :block node. Since ruby_parser ASTs for method definitions don't contain
  # such a node, remove it.
  if ast.nil?
    ast = []
  elsif ast.sexp_type == :block
    ast = ast.sexp_body
  else
    ast = [ast]
  end
  ast = s(:defn, meth_name.to_sym, s(:args), *ast)
  unless self.respond_to? :__bloom_asts__
    def self.__bloom_asts__
      @__bloom_asts__ ||= {}
      @__bloom_asts__
    end
  end
  __bloom_asts__[meth_name] = ast
  define_method(meth_name.to_sym, &block)
end

#bootstrap(&block) ⇒ Object

a ruby block to be run before timestep 1. one per module.



162
163
164
165
# File 'lib/bud/monkeypatch.rb', line 162

def bootstrap(&block)
  meth_name = "__bootstrap__#{Module.get_class_name(self)}".to_sym
  define_method(meth_name, &block)
end

#bud_import_tableObject

:nodoc: all



150
151
152
153
# File 'lib/bud/monkeypatch.rb', line 150

def bud_import_table() #:nodoc: all
  @bud_import_tbl ||= {}
  @bud_import_tbl
end

#import(spec) ⇒ Object

import another module and assign to a qualifier symbol: import MyModule => :m

Raises:



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/bud/monkeypatch.rb', line 106

def import(spec)
  raise Bud::CompileError unless (spec.class <= Hash and spec.length == 1)
  mod, local_name = spec.first
  raise Bud::CompileError unless (mod.class <= Module and local_name.class <= Symbol)
  if mod.class <= Class
    raise Bud::CompileError, "import must be used with a Module, not a Class"
  end

  # A statement like this:
  #   import MyModule => :m
  # is translated as follows. First, module MyModule is made instantiable by wrapping it in a class
  #   class MyModule__wrap__
  #     include Bud
  #     include MyModule
  #   end
  #
  # Then introduce a method "m", the import binding name, in the calling module/class
  # (the one with the import statement). This returns an instance of the wrapped class.
  #   inst = MyModule__wrap__.new
  #   def m
  #      inst
  #   end

  mod, local_name = spec.first

  if self.method_defined? local_name
    raise Bud::CompileError, "#{local_name} is already taken"
  else
    src = %Q{
      def #{local_name}
        @#{local_name}
      end
      def #{local_name}=(val)
        raise Bud::Error, "type error: expecting an instance of #{mod}" unless val.kind_of? #{mod}
        @#{local_name} = val
      end
    }
    self.class_eval src
  end

  import_tbl = self.bud_import_table
  import_tbl[local_name] = mod
end

#modulesObject



101
102
103
# File 'lib/bud/monkeypatch.rb', line 101

def modules
  ancestors[1..-1]
end

#state(&block) ⇒ Object

the block of Bloom collection declarations. one per module.



156
157
158
159
# File 'lib/bud/monkeypatch.rb', line 156

def state(&block)
  meth_name = Module.make_state_meth_name(self)
  define_method(meth_name, &block)
end