Skip to content

Instantly share code, notes, and snippets.

@baweaver
Created December 27, 2018 03:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baweaver/b710b52a1b64302ca1f1d13fba76aa93 to your computer and use it in GitHub Desktop.
Save baweaver/b710b52a1b64302ca1f1d13fba76aa93 to your computer and use it in GitHub Desktop.
Redux of Stack Functions, testing a few things out
class Sf
attr_reader :operations
def initialize(operations)
@operations = operations
end
def self.method_missing(method_name, *args, **kwargs, &fn)
p where: 'self.method_missing', method_name: method_name, args: args, kwargs: kwargs, fn: fn
self.new([method_name: method_name, args: args, kwargs: kwargs, fn: fn])
end
def method_missing(method_name, *args, **kwargs, &fn)
p where: 'method_missing', method_name: method_name, args: args, kwargs: kwargs, fn: fn
@operations.push(method_name: method_name, args: args, kwargs: kwargs, fn: fn)
self
end
def to_proc
-> object { call(object) }
end
def call(object)
@operations.reduce(object) { |obj, method_name:, args:, kwargs:, fn:|
p where: 'call', obj: obj, method_name: method_name, args: args, kwargs: kwargs, fn: fn
obj.public_send(method_name, *args, **kwargs, &fn)
}
end
def ===(object)
call(object)
end
end
[15] pry(main)> Sf + 5 * 10
{:where=>"self.method_missing", :method_name=>:+, :args=>[50], :kwargs=>{}, :fn=>nil}
=> #<Sf:0x00007fa579bb9718 @operations=[{:method_name=>:+, :args=>[50], :kwargs=>{}, :fn=>nil}]>
[16] pry(main)> puts RubyVM::InstructionSequence.disasm -> { Sf + 5 * 10 }
# == disasm: #<ISeq:block in __pry__@(pry):90 (90,42)-(90,58)> (catch: FALSE)
# == catch table
# | catch type: redo st: 0001 ed: 0018 sp: 0000 cont: 0001
# | catch type: next st: 0001 ed: 0018 sp: 0000 cont: 0018
# |------------------------------------------------------------------------
# 0000 nop ( 90)[Bc]
# 0001 opt_getinlinecache 8, <is:0>[Li]
# 0004 getconstant :Sf
# 0006 opt_setinlinecache <is:0>
# 0008 putobject 5
# 0010 putobject 10
# 0012 opt_mult <callinfo!mid:*, argc:1, ARGS_SIMPLE>, <callcache>
# 0015 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
# 0018 nop
# 0019 leave ( 90)[Br]
[17] pry(main)> Sf * 5 * 10
{:where=>"self.method_missing", :method_name=>:*, :args=>[5], :kwargs=>{}, :fn=>nil}
{:where=>"method_missing", :method_name=>:*, :args=>[10], :kwargs=>{}, :fn=>nil}
=> #<Sf:0x00007fa579a32818
@operations=
[{:method_name=>:*, :args=>[5], :kwargs=>{}, :fn=>nil}, {:method_name=>:*, :args=>[10], :kwargs=>{}, :fn=>nil}]>
[18] pry(main)> puts RubyVM::InstructionSequence.disasm -> { Sf * 5 * 10 }
# == disasm: #<ISeq:block in __pry__@(pry):92 (92,42)-(92,58)> (catch: FALSE)
# == catch table
# | catch type: redo st: 0001 ed: 0018 sp: 0000 cont: 0001
# | catch type: next st: 0001 ed: 0018 sp: 0000 cont: 0018
# |------------------------------------------------------------------------
# 0000 nop ( 92)[Bc]
# 0001 opt_getinlinecache 8, <is:0>[Li]
# 0004 getconstant :Sf
# 0006 opt_setinlinecache <is:0>
# 0008 putobject 5
# 0010 opt_mult <callinfo!mid:*, argc:1, ARGS_SIMPLE>, <callcache>
# 0013 putobject 10
# 0015 opt_mult <callinfo!mid:*, argc:1, ARGS_SIMPLE>, <callcache>
# 0018 nop
# 0019 leave ( 92)[Br]
@baweaver
Copy link
Author

v2 of extra hacky hack:

class Sf
  attr_reader :operations

  OPERATORS = %i(+ - * / % < > <= >= == && & || |)

  INSTANCE_OP = -> name {
    -> *args, **kwargs, &fn {
      p where: "instance.#{name}", method_name: name, args: args, kwargs: kwargs, fn: fn

      @operations.push(method_name: name, args: args, kwargs: kwargs, fn: fn)
    }
  }

  CLASS_OP = -> name {
    -> *args, **kwargs, &fn {
      p where: "class.#{name}", method_name: name, args: args, kwargs: kwargs, fn: fn

      self.new([method_name: name, args: args, kwargs: kwargs, fn: fn])
    }
  }

  OPERATORS.each do |op|
    self.define_method(op, &INSTANCE_OP[op])
    singleton_class.define_method(op, &CLASS_OP[op])
  end

  def method_missing(method_name, *args, **kwargs, &fn)
    self.define_method(method_name, &INSTANCE_OP[method_name])
    INSTANCE_OP[method_name].call(*args, **kwargs, &fn)
  end

  def self.method_missing(method_name, *args, **kwargs, &fn)
    singleton_class.define_method(method_name, &CLASS_OP[method_name])
    CLASS_OP[method_name].call(*args, **kwargs, &fn)
  end

  def initialize(operations)
    @operations = operations
  end

  def to_proc
    -> object { call(object) }
  end

  def call(object)
    @operations.reduce(object) { |obj, method_name:, args:, kwargs:, fn:|
      p where: 'call', obj: obj, method_name: method_name, args: args, kwargs: kwargs, fn: fn

      obj.public_send(method_name, *args, **kwargs, &fn)
    }
  end

  def ===(object)
    call(object)
  end
end

[2] pry(main)> Sf * 5 * 10

{:where=>"class.*", :method_name=>:*, :args=>[5], :kwargs=>{}, :fn=>nil}
{:where=>"instance.*", :method_name=>:*, :args=>[10], :kwargs=>{}, :fn=>nil}

=> [{:method_name=>:*, :args=>[5], :kwargs=>{}, :fn=>nil}, {:method_name=>:*, :args=>[10], :kwargs=>{}, :fn=>nil}]

[3] pry(main)> Sf + 5 * 10

{:where=>"class.+", :method_name=>:+, :args=>[50], :kwargs=>{}, :fn=>nil}

=> #<Sf:0x00007f8b7614b988 @operations=[{:method_name=>:+, :args=>[50], :kwargs=>{}, :fn=>nil}]>

[4] pry(main)> Sf * 5 + 10

{:where=>"class.*", :method_name=>:*, :args=>[5], :kwargs=>{}, :fn=>nil}
{:where=>"instance.+", :method_name=>:+, :args=>[10], :kwargs=>{}, :fn=>nil}

=> [{:method_name=>:*, :args=>[5], :kwargs=>{}, :fn=>nil}, {:method_name=>:+, :args=>[10], :kwargs=>{}, :fn=>nil}]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment