From b60524078d200fd02c847771cb65ae13207b2ea2 Mon Sep 17 00:00:00 2001 From: seancookr Date: Tue, 11 Oct 2016 10:56:10 -0700 Subject: [PATCH 1/7] create a constructor for sub properties --- lib/dolly/document.rb | 9 ++++++++- lib/dolly/property.rb | 19 ++++++++++++++++++- test/document_test.rb | 4 +++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/dolly/document.rb b/lib/dolly/document.rb index 6ad2641..e7b2f4a 100644 --- a/lib/dolly/document.rb +++ b/lib/dolly/document.rb @@ -143,9 +143,16 @@ def self.property *ary options = ary.pop if ary.last.kind_of? Hash options ||= {} - ary.each do |name| + if ary.count==1 && options[:class_name] == Hash && block_given? + name = ary.first self.properties[name] = Property.new options.merge(name: name) self.write_methods name + yield self.properties[name] + else + ary.each do |name| + self.properties[name] = Property.new options.merge(name: name) + self.write_methods name + end end end diff --git a/lib/dolly/property.rb b/lib/dolly/property.rb index 27c89a5..f47e79f 100644 --- a/lib/dolly/property.rb +++ b/lib/dolly/property.rb @@ -16,7 +16,6 @@ def initialize opts = {} end def value - #TODO: tets if this actually sets `doc[ "name" ]` return @default if @value.nil? return @value unless self_klass @@ -27,6 +26,22 @@ def value self.send klass_sym end + def subproperty *ary + @sub_properties ||= {} + options = ary.pop if ary.last.kind_of? Hash + options ||= {} + + if ary.count==1 && options[:class_name] == Hash && block_given? + name = ary.first + @sub_properties[name] = SubProperty.new options.merge(name: name) + yield self.properties[:name] + else + ary.each do |name| + @sub_properties[name] = SubProperty.new options.merge(name: name) + end + end + end + def array_value @value.to_a end @@ -82,4 +97,6 @@ def self_klass end end + + class SubProperty < Property; end end diff --git a/test/document_test.rb b/test/document_test.rb index f1c9cfe..a728230 100644 --- a/test/document_test.rb +++ b/test/document_test.rb @@ -21,7 +21,9 @@ class FooBar < BaseDolly class Baz < Dolly::Document; end class FooBaz < Dolly::Document - property :foo, class_name: Hash, default: {} + property :foo, class_name: Hash, default: {} do |property| + property.subproperty :bar, class_name: Array, default: [] + end def add_to_foo key, value foo[key] ||= value From 1f306cde3e707f00691ac52b749e0e2826afa1f5 Mon Sep 17 00:00:00 2001 From: seancookr Date: Tue, 11 Oct 2016 16:08:21 -0700 Subject: [PATCH 2/7] add a test for sub property concept --- lib/dolly/document.rb | 3 +-- lib/dolly/property.rb | 32 ++++++++++++++++++++------------ test/document_test.rb | 6 ++++++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/dolly/document.rb b/lib/dolly/document.rb index e7b2f4a..09b7e6b 100644 --- a/lib/dolly/document.rb +++ b/lib/dolly/document.rb @@ -194,8 +194,7 @@ def init_properties options = {} def initialize_default_properties options _properties.reject { |property| options.keys.include? property.name }.each do |property| - property_value = property.default.clone unless Dolly::Property::CANT_CLONE.any? { |klass| property.default.is_a? klass } - property_value ||= property.default + property_value = property.value.clone unless Dolly::Property::CANT_CLONE.any? { |klass| property.default.is_a? klass } self.doc[property.name] ||= property_value end end diff --git a/lib/dolly/property.rb b/lib/dolly/property.rb index f47e79f..76f32ac 100644 --- a/lib/dolly/property.rb +++ b/lib/dolly/property.rb @@ -2,7 +2,7 @@ module Dolly class Property attr_writer :value attr_accessor :name - attr_reader :class_name, :default + attr_reader :class_name, :default, :subproperties CANT_CLONE = [NilClass, TrueClass, FalseClass, Fixnum].freeze @@ -12,32 +12,40 @@ def initialize opts = {} @default = opts.delete(:default) @default = @default.clone if @default && CANT_CLONE.none? { |klass| @default.is_a? klass } @value = @default if @default + @subproperties ||= {} warn 'There are some unprocessed options!' if opts.present? end def value - return @default if @value.nil? - return @value unless self_klass + if subproperties.any? + @value ||= self_klass.new + subproperties.each do |name, subproperty| + @value[name.to_s] = subproperty.value + end + @value + else + return @default if @value.nil? + return @value unless self_klass - klass_sym = :"#{self_klass.name.underscore}_#{__method__}" + klass_sym = :"#{self_klass.name.underscore}_#{__method__}" - return self_klass.new @value unless self.respond_to?(klass_sym) + return self_klass.new @value unless self.respond_to?(klass_sym) - self.send klass_sym + self.send klass_sym + end end def subproperty *ary - @sub_properties ||= {} - options = ary.pop if ary.last.kind_of? Hash - options ||= {} + options = ary.pop if ary.last.kind_of? Hash + options ||= {} if ary.count==1 && options[:class_name] == Hash && block_given? name = ary.first - @sub_properties[name] = SubProperty.new options.merge(name: name) - yield self.properties[:name] + @subproperties[name] = SubProperty.new options.merge(name: name) + yield self.properties[name] else ary.each do |name| - @sub_properties[name] = SubProperty.new options.merge(name: name) + @subproperties[name] = SubProperty.new options.merge(name: name) end end end diff --git a/test/document_test.rb b/test/document_test.rb index a728230..941a35b 100644 --- a/test/document_test.rb +++ b/test/document_test.rb @@ -500,6 +500,12 @@ def setup assert_equal 1, bar.a end + test 'subproperty is populated on initialize' do + instance = FooBaz.new + expected = {'bar' => []} + assert_equal expected, instance.foo + end + private def generic_response rows, count = 1 {total_rows: count, offset:0, rows: rows} From 27565d84dedbdb6de2464400fcefd628bf125f74 Mon Sep 17 00:00:00 2001 From: seancookr Date: Tue, 11 Oct 2016 16:10:36 -0700 Subject: [PATCH 3/7] add 1 more thing in --- lib/dolly/document.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dolly/document.rb b/lib/dolly/document.rb index 09b7e6b..759173c 100644 --- a/lib/dolly/document.rb +++ b/lib/dolly/document.rb @@ -195,6 +195,7 @@ def init_properties options = {} def initialize_default_properties options _properties.reject { |property| options.keys.include? property.name }.each do |property| property_value = property.value.clone unless Dolly::Property::CANT_CLONE.any? { |klass| property.default.is_a? klass } + property_value ||= property.default self.doc[property.name] ||= property_value end end From 8c41fce91abbcc4a8e8a180fbeed8323e1343d6d Mon Sep 17 00:00:00 2001 From: seancookr Date: Tue, 11 Oct 2016 21:52:03 -0700 Subject: [PATCH 4/7] test for nested subproperties --- lib/dolly/property.rb | 4 ++-- test/document_test.rb | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/dolly/property.rb b/lib/dolly/property.rb index 76f32ac..f5ae5cf 100644 --- a/lib/dolly/property.rb +++ b/lib/dolly/property.rb @@ -12,7 +12,7 @@ def initialize opts = {} @default = opts.delete(:default) @default = @default.clone if @default && CANT_CLONE.none? { |klass| @default.is_a? klass } @value = @default if @default - @subproperties ||= {} + @subproperties = {} warn 'There are some unprocessed options!' if opts.present? end @@ -42,7 +42,7 @@ def subproperty *ary if ary.count==1 && options[:class_name] == Hash && block_given? name = ary.first @subproperties[name] = SubProperty.new options.merge(name: name) - yield self.properties[name] + yield self.subproperties[name] else ary.each do |name| @subproperties[name] = SubProperty.new options.merge(name: name) diff --git a/test/document_test.rb b/test/document_test.rb index 941a35b..066f2cf 100644 --- a/test/document_test.rb +++ b/test/document_test.rb @@ -23,6 +23,7 @@ class Baz < Dolly::Document; end class FooBaz < Dolly::Document property :foo, class_name: Hash, default: {} do |property| property.subproperty :bar, class_name: Array, default: [] + property.subproperty :baz, class_name: Hash, default: Hash.new end def add_to_foo key, value @@ -502,7 +503,7 @@ def setup test 'subproperty is populated on initialize' do instance = FooBaz.new - expected = {'bar' => []} + expected = {"bar"=>[], "baz"=>{}} assert_equal expected, instance.foo end From 2bc602fcae6b8b4608b8e91d3512dbbaa0af525e Mon Sep 17 00:00:00 2001 From: seancookr Date: Tue, 11 Oct 2016 21:59:58 -0700 Subject: [PATCH 5/7] test for nested subproperties --- test/document_test.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/document_test.rb b/test/document_test.rb index 066f2cf..7b89da5 100644 --- a/test/document_test.rb +++ b/test/document_test.rb @@ -23,7 +23,9 @@ class Baz < Dolly::Document; end class FooBaz < Dolly::Document property :foo, class_name: Hash, default: {} do |property| property.subproperty :bar, class_name: Array, default: [] - property.subproperty :baz, class_name: Hash, default: Hash.new + property.subproperty :baz, class_name: Hash, default: Hash.new do |sp| + sp.subproperty :far, class_name: Hash, default: Hash.new + end end def add_to_foo key, value @@ -501,9 +503,9 @@ def setup assert_equal 1, bar.a end - test 'subproperty is populated on initialize' do + test 'subproperties and children subprops are populated on initialize un' do instance = FooBaz.new - expected = {"bar"=>[], "baz"=>{}} + expected = {"bar"=>[], "baz"=>{"far"=>{}}} assert_equal expected, instance.foo end From 1210a56365478e0528514de4912cba88443ebfc2 Mon Sep 17 00:00:00 2001 From: seancookr Date: Fri, 14 Oct 2016 09:58:49 -0700 Subject: [PATCH 6/7] subproperties can be defined on multiple properties at once --- lib/dolly/document.rb | 18 ++++++++++-------- lib/dolly/property.rb | 41 ++++++++++++++++++++--------------------- test/document_test.rb | 15 ++++++++++++++- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/lib/dolly/document.rb b/lib/dolly/document.rb index 759173c..dbee14e 100644 --- a/lib/dolly/document.rb +++ b/lib/dolly/document.rb @@ -143,16 +143,13 @@ def self.property *ary options = ary.pop if ary.last.kind_of? Hash options ||= {} - if ary.count==1 && options[:class_name] == Hash && block_given? - name = ary.first - self.properties[name] = Property.new options.merge(name: name) - self.write_methods name - yield self.properties[name] - else + if options[:class_name] == Hash && block_given? ary.each do |name| - self.properties[name] = Property.new options.merge(name: name) - self.write_methods name + init_property name, options + yield self.properties[name] end + else + ary.each { |name| init_property name, options } end end @@ -192,6 +189,11 @@ def init_properties options = {} init_doc options end + def self.init_property name, opts={} + self.properties[name] = Property.new opts.merge(name: name) + self.write_methods name + end + def initialize_default_properties options _properties.reject { |property| options.keys.include? property.name }.each do |property| property_value = property.value.clone unless Dolly::Property::CANT_CLONE.any? { |klass| property.default.is_a? klass } diff --git a/lib/dolly/property.rb b/lib/dolly/property.rb index f5ae5cf..d6cec0b 100644 --- a/lib/dolly/property.rb +++ b/lib/dolly/property.rb @@ -11,38 +11,24 @@ def initialize opts = {} @name = opts.delete(:name).to_s @default = opts.delete(:default) @default = @default.clone if @default && CANT_CLONE.none? { |klass| @default.is_a? klass } - @value = @default if @default @subproperties = {} warn 'There are some unprocessed options!' if opts.present? end def value - if subproperties.any? - @value ||= self_klass.new - subproperties.each do |name, subproperty| - @value[name.to_s] = subproperty.value - end - @value - else - return @default if @value.nil? - return @value unless self_klass - - klass_sym = :"#{self_klass.name.underscore}_#{__method__}" - - return self_klass.new @value unless self.respond_to?(klass_sym) - - self.send klass_sym - end + return value_if_subproperties if subproperties.any? + standard_value end def subproperty *ary options = ary.pop if ary.last.kind_of? Hash options ||= {} - if ary.count==1 && options[:class_name] == Hash && block_given? - name = ary.first - @subproperties[name] = SubProperty.new options.merge(name: name) - yield self.subproperties[name] + if options[:class_name] == Hash && block_given? + ary.each do |name| + @subproperties[name] = SubProperty.new options.merge(name: name) + yield self.subproperties[name] + end else ary.each do |name| @subproperties[name] = SubProperty.new options.merge(name: name) @@ -104,6 +90,19 @@ def self_klass @class_name.is_a?(Class)? @class_name : @class_name.constantize end + def value_if_subproperties + @value ||= self_klass.new.tap do |v| + subproperties.each { |name, subproperty| v[name.to_s] = subproperty.value } + end + end + + def standard_value + return @default if @value.nil? + klass_sym = :"#{self_klass.name.underscore}_#{__method__}" + return self_klass.new @value unless self.respond_to?(klass_sym) + self.send klass_sym + end + end class SubProperty < Property; end diff --git a/test/document_test.rb b/test/document_test.rb index 7b89da5..5f23a8a 100644 --- a/test/document_test.rb +++ b/test/document_test.rb @@ -58,6 +58,12 @@ class Bar < FooBar property :a, :b end +class SubPropertyDocument < Dolly::Document + property :foo, :bar, class_name: Hash, default: {} do |property| + property.subproperty :baz, class_name: Hash, default: Hash.new + end +end + class DocumentTest < ActiveSupport::TestCase DB_BASE_PATH = "http://localhost:5984/test".freeze @@ -503,12 +509,19 @@ def setup assert_equal 1, bar.a end - test 'subproperties and children subprops are populated on initialize un' do + test 'subproperties and children subprops are populated on initialize' do instance = FooBaz.new expected = {"bar"=>[], "baz"=>{"far"=>{}}} assert_equal expected, instance.foo end + test 'subproperties may be defined for multiple properties at once' do + instance = SubPropertyDocument.new + expected = {"baz"=>{}} + assert_equal expected, instance.foo + assert_equal expected, instance.bar + end + private def generic_response rows, count = 1 {total_rows: count, offset:0, rows: rows} From bac83ffcf01aec44884e116220e9e0b6f0fd3711 Mon Sep 17 00:00:00 2001 From: seancookr Date: Thu, 23 Feb 2017 19:02:11 -0800 Subject: [PATCH 7/7] add a simpler dsl --- lib/dolly/document.rb | 5 +++-- lib/dolly/property.rb | 4 ++-- test/document_test.rb | 12 ++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/dolly/document.rb b/lib/dolly/document.rb index dbee14e..d0bdc99 100644 --- a/lib/dolly/document.rb +++ b/lib/dolly/document.rb @@ -138,7 +138,7 @@ def self.create options = {} obj end - def self.property *ary + def self.property *ary, &block self.properties ||= {} options = ary.pop if ary.last.kind_of? Hash options ||= {} @@ -146,7 +146,8 @@ def self.property *ary if options[:class_name] == Hash && block_given? ary.each do |name| init_property name, options - yield self.properties[name] + property = self.properties[name] + property.instance_exec(property, &block) end else ary.each { |name| init_property name, options } diff --git a/lib/dolly/property.rb b/lib/dolly/property.rb index d6cec0b..7def60c 100644 --- a/lib/dolly/property.rb +++ b/lib/dolly/property.rb @@ -20,14 +20,14 @@ def value standard_value end - def subproperty *ary + def subproperty *ary, &block options = ary.pop if ary.last.kind_of? Hash options ||= {} if options[:class_name] == Hash && block_given? ary.each do |name| @subproperties[name] = SubProperty.new options.merge(name: name) - yield self.subproperties[name] + self.subproperties[name].instance_exec self.subproperties[name], &block end else ary.each do |name| diff --git a/test/document_test.rb b/test/document_test.rb index 5f23a8a..9869185 100644 --- a/test/document_test.rb +++ b/test/document_test.rb @@ -21,10 +21,10 @@ class FooBar < BaseDolly class Baz < Dolly::Document; end class FooBaz < Dolly::Document - property :foo, class_name: Hash, default: {} do |property| - property.subproperty :bar, class_name: Array, default: [] - property.subproperty :baz, class_name: Hash, default: Hash.new do |sp| - sp.subproperty :far, class_name: Hash, default: Hash.new + property :foo, class_name: Hash, default: {} do + subproperty :bar, class_name: Array, default: [] + subproperty :baz, class_name: Hash, default: Hash.new do + subproperty :far, class_name: Hash, default: Hash.new end end @@ -59,8 +59,8 @@ class Bar < FooBar end class SubPropertyDocument < Dolly::Document - property :foo, :bar, class_name: Hash, default: {} do |property| - property.subproperty :baz, class_name: Hash, default: Hash.new + property :foo, :bar, class_name: Hash, default: {} do + subproperty :baz, class_name: Hash, default: Hash.new end end