[~]$ irb -r ./event-struct.rb
Run options: --seed 53294
# Running:
....
Finished in 0.024471s, 163.4600 runs/s, 81.7300 assertions/s.
4 runs, 2 assertions, 0 failures, 0 errors, 0 skips
irb(main):002:0> SetAddress = Event.new(:street, :postcode)
=> SetAddress
irb(main):003:0> SetAddress.new("foo")
ArgumentError: wrong number of arguments (given 1, expected 0)
from /Users/leehambley/event-struct.rb:36:in `new'
from (irb):3
from /Users/leehambley/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'
irb(main):004:0> SetAddress.new(street: "foo")
ArgumentError: keys do not match expected list:
-- missing keys: [:postcode]
-- extra keys: []
from /Users/leehambley/event-struct.rb:93:in `block in <class:Event>'
from /Users/leehambley/event-struct.rb:38:in `new'
from /Users/leehambley/event-struct.rb:38:in `new'
from (irb):4
from /Users/leehambley/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'
irb(main):005:0> SetAddress.new(street: "foo", postcode: "1234")
=> #<SetAddress:0x007fbb0c121d98 @street="foo", @postcode="1234", @occurred_on=2016-11-17 19:16:59 UTC>
-
-
Save leehambley/cc686418ef0145bb5556a62e267fc511 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'byebug' | |
require 'time' | |
require 'timecop' | |
require 'minitest' | |
class Event | |
include Enumerable | |
class << self | |
alias_method :subclass_new, :new | |
end | |
def self.new(*attrs, &block) | |
attr_sym_names = attrs.push(:occurred_on).map do |a| | |
case a | |
when Symbol | |
a | |
when String | |
sym = a.to_sym | |
unless sym.kind_of? Symbol | |
raise TypeError, "#to_sym didn't return a symbol" | |
end | |
sym | |
else | |
raise TypeError, "#{a.inspect} is not a symbol" | |
end | |
end | |
klass = Class.new self do | |
attr_accessor(*attr_sym_names) | |
def self.new(**args, &block) | |
# args is a hash of key-value pairs representing the keyword arguments | |
return subclass_new(**args, &block) | |
end | |
const_set :EVENT_ATTRS, attr_sym_names | |
end | |
klass.module_eval(&block) if block | |
return klass | |
end | |
# def self.new(*attribute_names_as_symbols) | |
# c = Class.new | |
# l = attribute_names_as_symbols | |
# | |
# c.instance_eval { | |
# define_method(:initialize) do |**kwargs| | |
# unless kwargs.keys.sort == l.sort | |
# extra = kwargs.keys - l | |
# missing = l - kwargs.keys | |
# | |
# raise ArgumentError.new <<-MESSAGE | |
# keys do not match expected list: | |
# -- missing keys: #{missing} | |
# -- extra keys: #{extra} | |
# MESSAGE | |
# end | |
# | |
# kwargs.map do |k, v| | |
# instance_variable_set "@#{k}", v | |
# end | |
# end | |
# | |
# l.each do |sym| | |
# attr_reader sym | |
# end | |
# } | |
# | |
# c | |
# end | |
define_method(:initialize) do |**kwargs| | |
attrs = _attrs | |
unless kwargs.has_key? :occurred_on | |
kwargs.merge! occurred_on: Time.now.utc | |
end | |
unless kwargs.keys.sort == attrs.sort | |
extra = kwargs.keys - attrs | |
missing = attrs - kwargs.keys | |
raise ArgumentError.new <<-MESSAGE | |
keys do not match expected list: | |
-- missing keys: #{missing} | |
-- extra keys: #{extra} | |
MESSAGE | |
end | |
kwargs.map do |k, v| | |
instance_variable_set "@#{k}", v | |
end | |
end | |
private :initialize | |
private def _attrs # :nodoc: | |
return self.class::EVENT_ATTRS | |
end | |
end | |
class SetName < Event.new(:name); end | |
class SetNameEventTest < MiniTest::Test | |
def test_the_event_static_attr_list | |
puts = Event.new(:user)::EVENT_ATTRS | |
end | |
def test_the_event_class_happy_path | |
SetName.new(name: "Lee") | |
end | |
def test_implicit_occured_on | |
some_time = Time.now | |
Timecop.freeze(some_time) do | |
assert_equal some_time, SetName.new(name: "Lee").occurred_on | |
end | |
end | |
def test_explicit_occured_on | |
some_time = Time.parse("2013-11-06") | |
assert_equal some_time, SetName.new(name: "Lee", occurred_on: some_time).occurred_on | |
end | |
end | |
MiniTest.run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment