class Myco::Meme
Attributes
body[RW]
cache[RW]
expose[RW]
getter[RW]
metadata[R]
name[RW]
setter[RW]
target[RW]
var[RW]
Public Class Methods
new(target, name, body=nil, &blk)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 63 def initialize target, name, body=nil, &blk self.target = target self.name = name self.body = body if body self.body = blk if blk self.cache = false self.var = false self.expose = true @metadata = {} @caches = {} end
Public Instance Methods
bind()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 132 def bind @bound = true return if not @expose @target.memes[@name] = self # TODO: consider removing @target.include(::Myco::PrimitiveInstanceMethods) unless @target < ::Myco::PrimitiveInstanceMethods if @var bind_var_getter bind_var_setter @effective_body = @target.instance_method(@name).executable elsif @getter bind_var_getter @effective_body = @target.instance_method(@name).executable elsif @setter bind_var_setter @effective_body = @target.instance_method(@name).executable elsif @cache bind_cache_method @effective_body = @target.instance_method(@name).executable else cscope = @body.respond_to?(:scope) ? @body.scope : nil Myco.add_method(@target, @name, @body, cscope) end end
body=(value)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 77 def body= value case value when Rubinius::BlockEnvironment::AsMethod @body = value when Rubinius::Thunk @body = value when Rubinius::Executable @body = value @body.scope.set_myco_meme self when Rubinius::BlockEnvironment block_env = value block_env.change_name name block_env.constant_scope.set_myco_meme self @body = Rubinius::BlockEnvironment::AsMethod.new block_env when Proc block_env = value.block.dup block_env.change_name name block_env.constant_scope.set_myco_meme self \ unless block_env.constant_scope.myco_meme @body = Rubinius::BlockEnvironment::AsMethod.new block_env else raise ArgumentError, "Meme body must be a Rubinius::Executable, " \ "Rubinius::BlockEnvironment or a Proc; got: #{value.inspect}" end @effective_body = @body bind if @bound @body end
cache=(value)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 116 def cache= value @cache = value bind if @bound @cache end
inspect()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 59 def inspect to_s end
result(*args, &blk)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 160 def result *args, &blk result_for target.instance, *args, &blk end
result_for(obj, *args, &blk)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 164 def result_for obj, *args, &blk result = @effective_body.invoke @name, @target, obj, args, blk end
set_result_for(obj, result, *args, &blk)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 168 def set_result_for obj, result, *args, &blk raise "Can't set_result_for this Meme" unless @cache cache_key = [obj.hash, args.hash, blk.hash] @caches[cache_key] = result end
target=(value)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 109 def target= value @target = value @target.extend(MemeBindable) unless @target.is_a?(MemeBindable) bind if @bound @target end
to_proc()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 128 def to_proc Proc.__from_block__(@body.block_env) end
to_s()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 55 def to_s "#<#{self.class}:#{self.name.to_s}>" end
var=(value)
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 122 def var= value @var = value bind if @bound @var end
Private Instance Methods
bind_cache_method()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 176 def bind_cache_method ## # This dynamic method is nearly the same as Meme#result_for # (but written from the perspective of the receiver) # implemented in bytecode to avoid forwarding to another method # on the call stack. # TODO: move this bytecode generation to a helper method meme = self Myco.add_dynamic_method target, @name, '(myco_internal)' do |g| g.splat_index = 0 # *args invoke = g.new_label ret = g.new_label ## # meme = <this meme> # g.push_literal meme g.set_local 1 # meme g.pop ## # caches = <this meme's @caches> # g.push_literal @caches g.set_local 2 # caches g.pop ## # cache_key = [obj.hash, args.hash, blk.hash] # g.push_self; g.send :hash, 0 g.push_local 0; g.send :hash, 0 # args g.push_block; g.send :hash, 0 g.make_array 3 g.set_local 3 # cache_key g.pop ## # if caches.has_key?(cache_key) # return caches[cache_key] # end # g.push_local 2 # caches g.push_local 3 # cache_key g.send :has_key?, 1 g.goto_if_false invoke g.push_local 2 # caches g.push_local 3 # cache_key g.send :[], 1 g.goto ret ## # result = meme.body.invoke meme.name, @target, obj, args, blk # invoke.set! g.push_local 1 # meme g.send :body, 0 g.push_local 1; g.send :name, 0 # meme.name g.push_local 1; g.send :target, 0 # meme.target g.push_self g.push_local 0 # args g.push_block g.send :invoke, 5 g.set_local 4 # result g.pop ## # return (caches[cache_key] = result) # g.push_local 2 # caches g.push_local 3 # cache_key g.push_local 4 # result g.send :[]=, 2 ret.set! g.ret end end
bind_var_getter()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 258 def bind_var_getter # TODO: move this bytecode generation to a helper method meme = self Myco.add_dynamic_method target, @name, '(myco_internal)' do |g| get = g.new_label ret = g.new_label ## # meme = <this meme> # g.push_literal meme g.set_local 1 # meme g.pop ## # if __ivar_defined__(#{name}) # @#{name} = meme.body.invoke meme.name, @target, obj, [], nil # end # return @#{name} # g.push_self g.push_literal(:"@#{@name}") g.send(:__ivar_defined__, 1) g.goto_if_true(get) g.push_local 1 # meme g.send :body, 0 g.push_local 1; g.send :name, 0 # meme.name g.push_local 1; g.send :target, 0 # meme.target g.push_self g.make_array 0 g.push_nil g.send :invoke, 5 g.set_ivar(:"@#{@name}") g.goto(ret) get.set! g.push_ivar(:"@#{@name}") ret.set! # If this meme has a getter defined, use it if self.getter g.push_self g.push_local(1) # meme g.send(:getter, 0) g.rotate(3) g.send(:call_on_object, 2) end g.ret end end
bind_var_setter()
click to toggle source
# File lib/myco/bootstrap/meme.rb, line 314 def bind_var_setter # TODO: move this bytecode generation to a helper method meme = self # TODO: move this bytecode generation to a helper method Myco.add_dynamic_method target, :"#{@name}=", '(myco_internal)' do |g| g.total_args = 1 g.local_count = 1 g.push_local 0 # value # If this meme has a setter defined, use it if meme.setter g.push_self g.push_literal(meme) g.send(:setter, 0) g.rotate(3) g.send(:call_on_object, 2) end g.set_ivar(:"@#{@name}") g.ret end end