class Module
Public Class Methods
# File lib/bud/monkeypatch.rb, line 210 def self.__bloom_asts__ @__bloom_asts__ ||= {} @__bloom_asts__ end
Private Class Methods
Return a string with a version of the class name appropriate for embedding into a method name. Annoyingly, if you define class X nested inside class/module Y, X's class name is the string “Y::X”. We don't want to define method names with semicolons in them, so just return “X” instead.
# File lib/bud/monkeypatch.rb, line 224 def self.get_class_name(klass) (klass.name.nil? or klass.name == "") \ ? "Anon#{klass.object_id}" \ : klass.name.split("::").last end
State method blocks are named using an auto-incrementing counter. This is to ensure that we can rediscover the possible dependencies between these blocks after module import (see Bud#call_state_methods
).
# File lib/bud/monkeypatch.rb, line 233 def self.make_state_meth_name(klass) @state_meth_id ||= 0 r = "__state#{@state_meth_id}__#{Module.get_class_name(klass)}".to_sym @state_meth_id += 1 return r end
Public Instance Methods
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.
# 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
a ruby block to be run before timestep 1. one per module.
# 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
import another module and assign to a qualifier symbol: import MyModule => :m
# 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
# File lib/bud/monkeypatch.rb, line 101 def modules ancestors[1..-1] end
the block of Bloom collection declarations. one per module.
# File lib/bud/monkeypatch.rb, line 156 def state(&block) meth_name = Module.make_state_meth_name(self) define_method(meth_name, &block) end