Skip to content

Instantly share code, notes, and snippets.

@petitviolet
Last active January 12, 2020 14:57
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 petitviolet/7a91cd2c630c2a6342014fc53f3e71cc to your computer and use it in GitHub Desktop.
Save petitviolet/7a91cd2c630c2a6342014fc53f3e71cc to your computer and use it in GitHub Desktop.
Struct implemented with Ruby
module Rstruct
def self.new(*attributes)
names = caller.map do |stack|
# ".../hoge.rb:7:in `<module:Hoge>'"
if (m = stack.match(/\A.+in `<(module|class):(.+)>.+/))
m[2]
end
end.reject(&:nil?)
file_name, line_num = caller[0].split(':')
line_executed = File.readlines(file_name)[line_num.to_i - 1]
names << line_executed.match(/\A\s*(\S+)\s*=/)[1] # " Point = Rstruct.new(:x, :y)\n"
class_name = names.join('::')
Class.new.tap do |k|
k.class_eval <<~RUBY
def initialize(#{attributes.join(", ")})
#{attributes.map { |attr| "@#{attr} = #{attr}" }.join("\n")}
end
#{attributes.map { |attr| "attr_reader(:#{attr})" }.join("\n")}
def inspect
if #{attributes.empty?}
"#{class_name}"
else
__attrs = Array[#{attributes.map { |attr| "'#{attr}: ' + @#{attr}.to_s" }.join(", ")}].join(", ")
"#{class_name}(" + __attrs + ")"
end
end
alias :to_s :inspect
def deconstruct
[#{attributes.map { |attr| "@#{attr}" }.join(", ")}]
end
RUBY
end
end
end
require_relative './rstruct'
Value = Rstruct.new(:v)
puts Value.new(100)
# => Value(v: 100)
module Parent
Point = Rstruct.new(:x, :y)
end
puts Parent::Point.new(10, 20)
# => Parent::Point(x: 10, y: 20)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment