From 123bd5dc6870413bf8f95554b6064b7311405f39 Mon Sep 17 00:00:00 2001 From: Eamonn Webster Date: Sun, 4 Feb 2024 12:59:12 +0000 Subject: [PATCH 1/3] Allow block to be specified for cattr_reader, also add default param My use case is to a reader only class attribute, but then I must be able to specify the initial value with a block or via default: --- motion/core_ext/class/attribute_accessors.rb | 16 ++++-- .../core_ext/class/attribute_accessor_spec.rb | 56 +++++++++++++------ 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/motion/core_ext/class/attribute_accessors.rb b/motion/core_ext/class/attribute_accessors.rb index 0b0a6c2..a8058a0 100644 --- a/motion/core_ext/class/attribute_accessors.rb +++ b/motion/core_ext/class/attribute_accessors.rb @@ -33,7 +33,7 @@ def cattr_reader(*syms) raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/ class_exec do unless class_variable_defined?("@@#{sym}") - class_variable_set("@@#{sym}", nil) + class_variable_set("@@#{sym}", block_given? ? yield : options[:default]) end define_singleton_method sym do @@ -94,7 +94,7 @@ def cattr_writer(*syms) raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/ class_exec do unless class_variable_defined?("@@#{sym}") - class_variable_set("@@#{sym}", nil) + class_variable_set("@@#{sym}", block_given? ? yield : options[:default]) end define_singleton_method "#{sym}=" do |obj| @@ -109,7 +109,6 @@ def cattr_writer(*syms) end end end - send("#{sym}=", yield) if block_given? end end @@ -161,8 +160,17 @@ def cattr_writer(*syms) # end # # Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red] + # + # Or by specifying a default + # + # class Person + # cattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red] + # end + # + # Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red] + def cattr_accessor(*syms, &blk) - cattr_reader(*syms) + cattr_reader(*syms, &blk) cattr_writer(*syms, &blk) end end diff --git a/spec/motion-support/core_ext/class/attribute_accessor_spec.rb b/spec/motion-support/core_ext/class/attribute_accessor_spec.rb index 38e1d2c..ca829ee 100644 --- a/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +++ b/spec/motion-support/core_ext/class/attribute_accessor_spec.rb @@ -15,38 +15,60 @@ class CAttrAccessorDerived < CAttrAccessorBase cattr_accessor :bar, :instance_writer => false cattr_reader :shaq, :instance_reader => false cattr_accessor :camp, :instance_accessor => false + cattr_reader :rdrb do 'block' end + cattr_reader :rdrd, :default => 'default' end @object = @class.new end - + describe "reader" do it "should return nil by default" do @class.foo.should.be.nil end + + it "should return nil by default for instance" do + @object.foo.should.be.nil + end + + it "should return block if one was present" do + @class.rdrb.should == 'block' + end + + it "should return block if one was present for instance" do + @object.rdrb.should == 'block' + end + + it "should return default if one was specified" do + @class.rdrd.should == 'default' + end + + it "should return default if one was given for specified" do + @object.rdrd.should == 'default' + end end - + describe "writer" do it "should set value" do @class.foo = :test @class.foo.should == :test end - + it "should set value through instance writer" do @object.foo = :bar @object.foo.should == :bar end - + it "should set instance reader's value through module's writer" do @class.foo = :test @object.foo.should == :test end - + it "should set module reader's value through instances's writer" do @object.foo = :bar @class.foo.should == :bar end end - + describe "instance_writer => false" do it "should not create instance writer" do @class.should.respond_to :foo @@ -55,14 +77,14 @@ class CAttrAccessorDerived < CAttrAccessorBase @object.should.not.respond_to :bar= end end - + describe "instance_reader => false" do it "should not create instance reader" do @class.should.respond_to :shaq @object.should.not.respond_to :shaq end end - + describe "instance_accessor => false" do it "should not create reader or writer" do @class.should.respond_to :camp @@ -71,7 +93,7 @@ class CAttrAccessorDerived < CAttrAccessorBase end end end - + describe "invalid attribute accessors" do it "should raise NameError when creating an invalid reader" do lambda do @@ -80,7 +102,7 @@ class CAttrAccessorDerived < CAttrAccessorBase end end.should.raise NameError end - + it "should raise NameError when creating an invalid writer" do lambda do Class.new do @@ -89,36 +111,36 @@ class CAttrAccessorDerived < CAttrAccessorBase end.should.raise NameError end end - + describe "inheritance" do it "should be accessible in the base class and the derived class" do CAttrAccessorBase.respond_to?(:empty_accessor).should == true CAttrAccessorDerived.respond_to?(:empty_accessor).should == true end - + it "should return nil for an unset accessor in the base class" do CAttrAccessorBase.empty_accessor.should == nil end - + it "should return nil for an unset accessor in the derived class" do CAttrAccessorDerived.empty_accessor.should == nil end - + it "should return a value for an accessor set in the base class in the base class" do CAttrAccessorBase.base_accessor = 10 CAttrAccessorBase.base_accessor.should == 10 end - + it "should return a value for an accessor set in the base class in the derived class" do CAttrAccessorBase.base_accessor = 10 CAttrAccessorDerived.base_accessor.should == 10 end - + it "should return a value for the base class if set for the derived class" do CAttrAccessorDerived.derived_accessor = 20 CAttrAccessorBase.derived_accessor.should == 20 end - + it "should return a value for an accessor set in the derived class in the derived class" do CAttrAccessorDerived.derived_accessor = 20 CAttrAccessorDerived.derived_accessor.should == 20 From 8de3926d72934965b0bd35eff59713ae9bba59e3 Mon Sep 17 00:00:00 2001 From: Eamonn Webster Date: Tue, 6 Feb 2024 08:15:34 +0000 Subject: [PATCH 2/3] example description --- spec/motion-support/core_ext/class/attribute_accessor_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/motion-support/core_ext/class/attribute_accessor_spec.rb b/spec/motion-support/core_ext/class/attribute_accessor_spec.rb index ca829ee..427b653 100644 --- a/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +++ b/spec/motion-support/core_ext/class/attribute_accessor_spec.rb @@ -42,7 +42,7 @@ class CAttrAccessorDerived < CAttrAccessorBase @class.rdrd.should == 'default' end - it "should return default if one was given for specified" do + it "should return default if one was given for instance" do @object.rdrd.should == 'default' end end From 260f5a3495771d67ac79074ee34db6566117c7ae Mon Sep 17 00:00:00 2001 From: Eamonn Webster Date: Thu, 8 Feb 2024 23:18:15 +0000 Subject: [PATCH 3/3] Plain object, override to_json --- motion/duration.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/motion/duration.rb b/motion/duration.rb index 33d167b..e920dc2 100644 --- a/motion/duration.rb +++ b/motion/duration.rb @@ -3,7 +3,7 @@ module MotionSupport # Time#advance, respectively. It mainly supports the methods on Numeric. # # 1.month.ago # equivalent to Time.now.advance(months: -1) - class Duration < BasicObject + class Duration attr_accessor :value, :parts def initialize(value, parts) #:nodoc: @@ -79,7 +79,11 @@ def as_json(options = nil) #:nodoc: to_i end - protected + def to_json + as_json.to_json + end + + protected def sum(sign, time = ::Time.now) #:nodoc: parts.inject(time) do |t,(type,number)|