ardm 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +35 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +21 -0
  5. data/README.md +70 -0
  6. data/Rakefile +4 -0
  7. data/ardm.gemspec +29 -0
  8. data/db/.gitignore +1 -0
  9. data/lib/ardm/active_record/associations.rb +80 -0
  10. data/lib/ardm/active_record/base.rb +49 -0
  11. data/lib/ardm/active_record/dirty.rb +25 -0
  12. data/lib/ardm/active_record/hooks.rb +31 -0
  13. data/lib/ardm/active_record/inheritance.rb +37 -0
  14. data/lib/ardm/active_record/is/state_machine.rb +21 -0
  15. data/lib/ardm/active_record/is.rb +22 -0
  16. data/lib/ardm/active_record/not_found.rb +7 -0
  17. data/lib/ardm/active_record/predicate_builder/array_handler.rb +31 -0
  18. data/lib/ardm/active_record/predicate_builder/rails3.rb +147 -0
  19. data/lib/ardm/active_record/predicate_builder/rails4.rb +139 -0
  20. data/lib/ardm/active_record/predicate_builder/relation_handler.rb +15 -0
  21. data/lib/ardm/active_record/predicate_builder.rb +19 -0
  22. data/lib/ardm/active_record/property.rb +357 -0
  23. data/lib/ardm/active_record/query.rb +108 -0
  24. data/lib/ardm/active_record/record.rb +70 -0
  25. data/lib/ardm/active_record/relation.rb +83 -0
  26. data/lib/ardm/active_record/repository.rb +38 -0
  27. data/lib/ardm/active_record/serialization.rb +164 -0
  28. data/lib/ardm/active_record/storage_names.rb +28 -0
  29. data/lib/ardm/active_record/validations.rb +111 -0
  30. data/lib/ardm/active_record.rb +43 -0
  31. data/lib/ardm/data_mapper/not_found.rb +5 -0
  32. data/lib/ardm/data_mapper/record.rb +41 -0
  33. data/lib/ardm/data_mapper.rb +5 -0
  34. data/lib/ardm/env.rb +5 -0
  35. data/lib/ardm/property/api_key.rb +30 -0
  36. data/lib/ardm/property/bcrypt_hash.rb +31 -0
  37. data/lib/ardm/property/binary.rb +23 -0
  38. data/lib/ardm/property/boolean.rb +29 -0
  39. data/lib/ardm/property/class.rb +19 -0
  40. data/lib/ardm/property/comma_separated_list.rb +28 -0
  41. data/lib/ardm/property/csv.rb +35 -0
  42. data/lib/ardm/property/date.rb +12 -0
  43. data/lib/ardm/property/datetime.rb +12 -0
  44. data/lib/ardm/property/decimal.rb +38 -0
  45. data/lib/ardm/property/discriminator.rb +65 -0
  46. data/lib/ardm/property/enum.rb +51 -0
  47. data/lib/ardm/property/epoch_time.rb +38 -0
  48. data/lib/ardm/property/file_path.rb +25 -0
  49. data/lib/ardm/property/flag.rb +65 -0
  50. data/lib/ardm/property/float.rb +18 -0
  51. data/lib/ardm/property/integer.rb +24 -0
  52. data/lib/ardm/property/invalid_value_error.rb +22 -0
  53. data/lib/ardm/property/ip_address.rb +35 -0
  54. data/lib/ardm/property/json.rb +49 -0
  55. data/lib/ardm/property/lookup.rb +29 -0
  56. data/lib/ardm/property/numeric.rb +40 -0
  57. data/lib/ardm/property/object.rb +36 -0
  58. data/lib/ardm/property/paranoid_boolean.rb +18 -0
  59. data/lib/ardm/property/paranoid_datetime.rb +17 -0
  60. data/lib/ardm/property/regexp.rb +22 -0
  61. data/lib/ardm/property/serial.rb +16 -0
  62. data/lib/ardm/property/slug.rb +29 -0
  63. data/lib/ardm/property/string.rb +40 -0
  64. data/lib/ardm/property/support/dirty_minder.rb +169 -0
  65. data/lib/ardm/property/support/flags.rb +41 -0
  66. data/lib/ardm/property/support/paranoid_base.rb +78 -0
  67. data/lib/ardm/property/text.rb +11 -0
  68. data/lib/ardm/property/time.rb +12 -0
  69. data/lib/ardm/property/uri.rb +27 -0
  70. data/lib/ardm/property/uuid.rb +65 -0
  71. data/lib/ardm/property/validation.rb +208 -0
  72. data/lib/ardm/property/yaml.rb +38 -0
  73. data/lib/ardm/property.rb +891 -0
  74. data/lib/ardm/property_set.rb +152 -0
  75. data/lib/ardm/query/expression.rb +85 -0
  76. data/lib/ardm/query/ext/symbol.rb +37 -0
  77. data/lib/ardm/query/operator.rb +64 -0
  78. data/lib/ardm/record.rb +1 -0
  79. data/lib/ardm/support/assertions.rb +8 -0
  80. data/lib/ardm/support/deprecate.rb +12 -0
  81. data/lib/ardm/support/descendant_set.rb +89 -0
  82. data/lib/ardm/support/equalizer.rb +48 -0
  83. data/lib/ardm/support/ext/array.rb +22 -0
  84. data/lib/ardm/support/ext/blank.rb +25 -0
  85. data/lib/ardm/support/ext/hash.rb +67 -0
  86. data/lib/ardm/support/ext/module.rb +47 -0
  87. data/lib/ardm/support/ext/object.rb +57 -0
  88. data/lib/ardm/support/ext/string.rb +24 -0
  89. data/lib/ardm/support/ext/try_dup.rb +12 -0
  90. data/lib/ardm/support/hook.rb +405 -0
  91. data/lib/ardm/support/lazy_array.rb +451 -0
  92. data/lib/ardm/support/local_object_space.rb +13 -0
  93. data/lib/ardm/support/logger.rb +201 -0
  94. data/lib/ardm/support/mash.rb +176 -0
  95. data/lib/ardm/support/naming_conventions.rb +90 -0
  96. data/lib/ardm/support/ordered_set.rb +380 -0
  97. data/lib/ardm/support/subject.rb +33 -0
  98. data/lib/ardm/support/subject_set.rb +250 -0
  99. data/lib/ardm/version.rb +3 -0
  100. data/lib/ardm.rb +56 -0
  101. data/spec/fixtures/api_user.rb +11 -0
  102. data/spec/fixtures/article.rb +22 -0
  103. data/spec/fixtures/bookmark.rb +14 -0
  104. data/spec/fixtures/invention.rb +5 -0
  105. data/spec/fixtures/network_node.rb +23 -0
  106. data/spec/fixtures/person.rb +17 -0
  107. data/spec/fixtures/software_package.rb +22 -0
  108. data/spec/fixtures/ticket.rb +12 -0
  109. data/spec/fixtures/tshirt.rb +15 -0
  110. data/spec/integration/api_key_spec.rb +25 -0
  111. data/spec/integration/bcrypt_hash_spec.rb +45 -0
  112. data/spec/integration/comma_separated_list_spec.rb +85 -0
  113. data/spec/integration/dirty_minder_spec.rb +197 -0
  114. data/spec/integration/enum_spec.rb +79 -0
  115. data/spec/integration/epoch_time_spec.rb +59 -0
  116. data/spec/integration/file_path_spec.rb +158 -0
  117. data/spec/integration/flag_spec.rb +72 -0
  118. data/spec/integration/ip_address_spec.rb +151 -0
  119. data/spec/integration/json_spec.rb +70 -0
  120. data/spec/integration/slug_spec.rb +65 -0
  121. data/spec/integration/uri_spec.rb +136 -0
  122. data/spec/integration/uuid_spec.rb +102 -0
  123. data/spec/integration/yaml_spec.rb +85 -0
  124. data/spec/public/property/binary_spec.rb +41 -0
  125. data/spec/public/property/boolean_spec.rb +30 -0
  126. data/spec/public/property/class_spec.rb +28 -0
  127. data/spec/public/property/date_spec.rb +22 -0
  128. data/spec/public/property/date_time_spec.rb +22 -0
  129. data/spec/public/property/decimal_spec.rb +23 -0
  130. data/spec/public/property/discriminator_spec.rb +133 -0
  131. data/spec/public/property/float_spec.rb +22 -0
  132. data/spec/public/property/integer_spec.rb +22 -0
  133. data/spec/public/property/object_spec.rb +103 -0
  134. data/spec/public/property/serial_spec.rb +22 -0
  135. data/spec/public/property/string_spec.rb +22 -0
  136. data/spec/public/property/text_spec.rb +23 -0
  137. data/spec/public/property/time_spec.rb +22 -0
  138. data/spec/public/property_spec.rb +316 -0
  139. data/spec/rcov.opts +6 -0
  140. data/spec/schema.rb +86 -0
  141. data/spec/semipublic/property/binary_spec.rb +14 -0
  142. data/spec/semipublic/property/boolean_spec.rb +48 -0
  143. data/spec/semipublic/property/class_spec.rb +36 -0
  144. data/spec/semipublic/property/date_spec.rb +44 -0
  145. data/spec/semipublic/property/date_time_spec.rb +47 -0
  146. data/spec/semipublic/property/decimal_spec.rb +83 -0
  147. data/spec/semipublic/property/discriminator_spec.rb +22 -0
  148. data/spec/semipublic/property/float_spec.rb +83 -0
  149. data/spec/semipublic/property/integer_spec.rb +83 -0
  150. data/spec/semipublic/property/lookup_spec.rb +27 -0
  151. data/spec/semipublic/property/serial_spec.rb +14 -0
  152. data/spec/semipublic/property/string_spec.rb +14 -0
  153. data/spec/semipublic/property/text_spec.rb +30 -0
  154. data/spec/semipublic/property/time_spec.rb +49 -0
  155. data/spec/semipublic/property_spec.rb +51 -0
  156. data/spec/shared/flags_shared_spec.rb +36 -0
  157. data/spec/shared/identity_function_group.rb +5 -0
  158. data/spec/shared/public_property_spec.rb +229 -0
  159. data/spec/shared/semipublic_property_spec.rb +159 -0
  160. data/spec/spec.opts +4 -0
  161. data/spec/spec_helper.rb +58 -0
  162. data/spec/unit/bcrypt_hash_spec.rb +154 -0
  163. data/spec/unit/csv_spec.rb +139 -0
  164. data/spec/unit/dirty_minder_spec.rb +64 -0
  165. data/spec/unit/enum_spec.rb +125 -0
  166. data/spec/unit/epoch_time_spec.rb +72 -0
  167. data/spec/unit/file_path_spec.rb +75 -0
  168. data/spec/unit/flag_spec.rb +114 -0
  169. data/spec/unit/ip_address_spec.rb +109 -0
  170. data/spec/unit/json_spec.rb +127 -0
  171. data/spec/unit/paranoid_boolean_spec.rb +142 -0
  172. data/spec/unit/paranoid_datetime_spec.rb +149 -0
  173. data/spec/unit/regexp_spec.rb +62 -0
  174. data/spec/unit/uri_spec.rb +64 -0
  175. data/spec/unit/yaml_spec.rb +111 -0
  176. data/tasks/spec.rake +40 -0
  177. data/tasks/yard.rake +9 -0
  178. data/tasks/yardstick.rake +19 -0
  179. metadata +350 -0
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Discriminator do
4
+ before do
5
+ Object.send(:remove_const, :Foo) if defined?(Foo)
6
+ Object.send(:remove_const, :Bar) if defined?(Bar)
7
+
8
+ class ::Foo; end
9
+ class ::Bar; end
10
+ end
11
+
12
+ let(:name) { :type }
13
+ let(:type) { described_class }
14
+ let(:options) { {} }
15
+ let(:value) { Foo }
16
+ let(:other_value) { Bar }
17
+ let(:invalid_value) { 1 }
18
+ let(:model) { Blog::Article }
19
+ let(:property) { type.new(model, name, options) }
20
+
21
+ it_should_behave_like 'A semipublic Property'
22
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Float do
4
+ let(:name) { :rating }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { 0.1 }
8
+ let(:other_value) { 0.2 }
9
+ let(:invalid_value) { '1' }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#typecast' do
16
+ it 'returns same value if a float' do
17
+ value = 24.0
18
+ property.typecast(value).should equal(value)
19
+ end
20
+
21
+ it 'returns float representation of a zero string integer' do
22
+ property.typecast('0').should eql(0.0)
23
+ end
24
+
25
+ it 'returns float representation of a positive string integer' do
26
+ property.typecast('24').should eql(24.0)
27
+ end
28
+
29
+ it 'returns float representation of a negative string integer' do
30
+ property.typecast('-24').should eql(-24.0)
31
+ end
32
+
33
+ it 'returns float representation of a zero string float' do
34
+ property.typecast('0.0').should eql(0.0)
35
+ end
36
+
37
+ it 'returns float representation of a positive string float' do
38
+ property.typecast('24.35').should eql(24.35)
39
+ end
40
+
41
+ it 'returns float representation of a negative string float' do
42
+ property.typecast('-24.35').should eql(-24.35)
43
+ end
44
+
45
+ it 'returns float representation of a zero string float, with no leading digits' do
46
+ property.typecast('.0').should eql(0.0)
47
+ end
48
+
49
+ it 'returns float representation of a positive string float, with no leading digits' do
50
+ property.typecast('.41').should eql(0.41)
51
+ end
52
+
53
+ it 'returns float representation of a zero integer' do
54
+ property.typecast(0).should eql(0.0)
55
+ end
56
+
57
+ it 'returns float representation of a positive integer' do
58
+ property.typecast(24).should eql(24.0)
59
+ end
60
+
61
+ it 'returns float representation of a negative integer' do
62
+ property.typecast(-24).should eql(-24.0)
63
+ end
64
+
65
+ it 'returns float representation of a zero decimal' do
66
+ property.typecast(BigDecimal('0.0')).should eql(0.0)
67
+ end
68
+
69
+ it 'returns float representation of a positive decimal' do
70
+ property.typecast(BigDecimal('24.35')).should eql(24.35)
71
+ end
72
+
73
+ it 'returns float representation of a negative decimal' do
74
+ property.typecast(BigDecimal('-24.35')).should eql(-24.35)
75
+ end
76
+
77
+ [ Object.new, true, '0.', '-.0', 'string' ].each do |value|
78
+ it "does not typecast non-numeric value #{value.inspect}" do
79
+ property.typecast(value).should equal(value)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Integer do
4
+ let(:name) { :age }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { 1 }
8
+ let(:other_value) { 2 }
9
+ let(:invalid_value) { '1' }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#typecast' do
16
+ it 'returns same value if an integer' do
17
+ value = 24
18
+ property.typecast(value).should equal(value)
19
+ end
20
+
21
+ it 'returns integer representation of a zero string integer' do
22
+ property.typecast('0').should eql(0)
23
+ end
24
+
25
+ it 'returns integer representation of a positive string integer' do
26
+ property.typecast('24').should eql(24)
27
+ end
28
+
29
+ it 'returns integer representation of a negative string integer' do
30
+ property.typecast('-24').should eql(-24)
31
+ end
32
+
33
+ it 'returns integer representation of a zero string float' do
34
+ property.typecast('0.0').should eql(0)
35
+ end
36
+
37
+ it 'returns integer representation of a positive string float' do
38
+ property.typecast('24.35').should eql(24)
39
+ end
40
+
41
+ it 'returns integer representation of a negative string float' do
42
+ property.typecast('-24.35').should eql(-24)
43
+ end
44
+
45
+ it 'returns integer representation of a zero string float, with no leading digits' do
46
+ property.typecast('.0').should eql(0)
47
+ end
48
+
49
+ it 'returns integer representation of a positive string float, with no leading digits' do
50
+ property.typecast('.41').should eql(0)
51
+ end
52
+
53
+ it 'returns integer representation of a zero float' do
54
+ property.typecast(0.0).should eql(0)
55
+ end
56
+
57
+ it 'returns integer representation of a positive float' do
58
+ property.typecast(24.35).should eql(24)
59
+ end
60
+
61
+ it 'returns integer representation of a negative float' do
62
+ property.typecast(-24.35).should eql(-24)
63
+ end
64
+
65
+ it 'returns integer representation of a zero decimal' do
66
+ property.typecast(BigDecimal('0.0')).should eql(0)
67
+ end
68
+
69
+ it 'returns integer representation of a positive decimal' do
70
+ property.typecast(BigDecimal('24.35')).should eql(24)
71
+ end
72
+
73
+ it 'returns integer representation of a negative decimal' do
74
+ property.typecast(BigDecimal('-24.35')).should eql(-24)
75
+ end
76
+
77
+ [ Object.new, true, '0.', '-.0', 'string' ].each do |value|
78
+ it "does not typecast non-numeric value #{value.inspect}" do
79
+ property.typecast(value).should equal(value)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module LookupFoo
4
+ class OtherProperty < Ardm::Property::String; end
5
+ end
6
+
7
+ describe Ardm::Property::Lookup do
8
+ before do
9
+ @klass = Class.new(Ardm::Record) do
10
+ self.table_name = "articles"
11
+ end
12
+ end
13
+
14
+ it 'should provide access to Property classes' do
15
+ @klass::Serial.should == Ardm::Property::Serial
16
+ end
17
+
18
+ it 'should provide access to Property classes from outside of the Property namespace' do
19
+ @klass::OtherProperty.should eq(LookupFoo::OtherProperty)
20
+ end
21
+
22
+ it 'should not provide access to unknown Property classes' do
23
+ lambda {
24
+ @klass::Bla
25
+ }.should raise_error(NameError)
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Serial do
4
+ let(:name) { :id }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { 1 }
8
+ let(:other_value) { 2 }
9
+ let(:invalid_value) { 'foo' }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::String do
4
+ let(:name) { :name }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { 'value' }
8
+ let(:other_value) { 'return value' }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Text do
4
+ let(:name) { :title }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { 'value' }
8
+ let(:other_value) { 'return value' }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#load' do
16
+ before do
17
+ @value = 'value'
18
+ end
19
+
20
+ subject { property.load(@value) }
21
+
22
+ let(:property) { type.new(model, name) }
23
+
24
+ it 'should delegate to #type.load' do
25
+ return_value = 'return value'
26
+ property.should_receive(:load).with(@value).and_return(return_value)
27
+ subject.should == return_value
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Time do
4
+ let(:name) { :deleted_at }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { Time.now }
8
+ let(:other_value) { Time.now + 15 }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#typecast' do
16
+ describe 'and value given as a hash with keys like :year, :month, etc' do
17
+ it 'builds a Time instance from hash values' do
18
+ result = property.typecast(
19
+ :year => '2006',
20
+ :month => '11',
21
+ :day => '23',
22
+ :hour => '12',
23
+ :min => '0',
24
+ :sec => '0'
25
+ )
26
+
27
+ result.should be_kind_of(Time)
28
+ result.year.should eql(2006)
29
+ result.month.should eql(11)
30
+ result.day.should eql(23)
31
+ result.hour.should eql(12)
32
+ result.min.should eql(0)
33
+ result.sec.should eql(0)
34
+ end
35
+ end
36
+
37
+ describe 'and value is a string' do
38
+ it 'parses the string' do
39
+ result = property.typecast('22:24')
40
+ result.hour.should eql(22)
41
+ result.min.should eql(24)
42
+ end
43
+ end
44
+
45
+ it 'does not typecast non-time values' do
46
+ property.typecast('not-time').should eql('not-time')
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ # instance methods
4
+ describe Ardm::Property do
5
+ describe ".find_class" do
6
+ [ :Serial, :Text ].each do |type|
7
+ describe "with #{type}" do
8
+ subject { Ardm::Property.find_class(type) }
9
+
10
+ it { subject.should be(Ardm::Property.const_get(type)) }
11
+ end
12
+ end
13
+ end
14
+
15
+ describe ".determine_class" do
16
+ [ Integer, String, Float, Class, String, Time, DateTime, Date ].each do |type|
17
+ describe "with #{type}" do
18
+ subject { Ardm::Property.determine_class(type) }
19
+
20
+ it { subject.should be(Ardm::Property.const_get(type.name)) }
21
+ end
22
+ end
23
+
24
+ describe "with property subclasses" do
25
+ before do
26
+ Object.send(:remove_const, :CustomProps) if Object.const_defined?(:CustomProps)
27
+
28
+ module ::CustomProps
29
+ module Property
30
+ class Hash < Ardm::Property::Object; end
31
+ class Other < Ardm::Property::Object; end
32
+ class Serial < Ardm::Property::Object; end
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "with ::Foo::Property::Hash" do
38
+ subject { Ardm::Property.determine_class(Hash) }
39
+
40
+ it { subject.should be(::CustomProps::Property::Hash) }
41
+ end
42
+
43
+ describe "with ::Foo::Property::Other" do
44
+ subject { Ardm::Property.determine_class(::CustomProps::Property::Other) }
45
+
46
+ it { subject.should be(::CustomProps::Property::Other) }
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ share_examples_for "A property with flags" do
2
+ before do
3
+ %w[ @property_klass ].each do |ivar|
4
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
5
+ end
6
+
7
+ @flags = [ :one, :two, :three ]
8
+
9
+ class ::User < Ardm::Record
10
+ end
11
+
12
+ @property = User.property :item, @property_klass[@flags], :key => true
13
+ end
14
+
15
+ describe ".generated_classes" do
16
+ it "should cache the generated class" do
17
+ @property_klass.generated_classes[@flags].should_not be_nil
18
+ end
19
+ end
20
+
21
+ it "should include :flags in accepted_options" do
22
+ @property_klass.accepted_options.should include(:flags)
23
+ end
24
+
25
+ it "should respond to :generated_classes" do
26
+ @property_klass.should respond_to(:generated_classes)
27
+ end
28
+
29
+ it "should respond to :flag_map" do
30
+ @property.should respond_to(:flag_map)
31
+ end
32
+
33
+ it "should be custom" do
34
+ @property.custom?.should be(true)
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ shared_examples_for "identity function" do
2
+ it "returns value unchanged" do
3
+ @result.should == @input
4
+ end
5
+ end
@@ -0,0 +1,229 @@
1
+ share_examples_for 'A public Property' do
2
+ before do
3
+ %w[ @type @load_as @name @value @other_value ].each do |ivar|
4
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
5
+ end
6
+
7
+ module ::Blog
8
+ class Article < Ardm::Record
9
+ self.table_name = "articles"
10
+ property :id, Serial
11
+ end
12
+ end
13
+
14
+ @model = Blog::Article
15
+ @options ||= {}
16
+ end
17
+
18
+ describe "with a sub-type" do
19
+ before do
20
+ class ::SubType < @type; end
21
+ @subtype = ::SubType
22
+ @type.accept_options :foo, :bar
23
+ end
24
+
25
+ before do
26
+ @original = @type.accepted_options.dup
27
+ end
28
+
29
+ after do
30
+ @type.accepted_options.replace(@original - [ :foo, :bar ])
31
+ end
32
+
33
+ describe "predefined options" do
34
+ before do
35
+ class ::ChildSubType < @subtype
36
+ default nil
37
+ end
38
+ @child_subtype = ChildSubType
39
+ end
40
+
41
+ describe "when parent type overrides a default" do
42
+ before do
43
+ @subtype.default "foo"
44
+ end
45
+
46
+ after do
47
+ Ardm::Property.descendants.delete(ChildSubType)
48
+ Object.send(:remove_const, :ChildSubType)
49
+ end
50
+
51
+ it "should not override the child's type setting" do
52
+ @child_subtype.default.should eql(nil)
53
+ end
54
+ end
55
+ end
56
+
57
+ after do
58
+ Ardm::Property.descendants.delete(SubType)
59
+ Object.send(:remove_const, :SubType)
60
+ end
61
+
62
+ describe ".accept_options" do
63
+ describe "when provided :foo, :bar" do
64
+ it "should add new options" do
65
+ [@type, @subtype].each do |type|
66
+ type.accepted_options.include?(:foo).should be(true)
67
+ type.accepted_options.include?(:bar).should be(true)
68
+ end
69
+ end
70
+
71
+ it "should create predefined option setters" do
72
+ [@type, @subtype].each do |type|
73
+ type.should respond_to(:foo)
74
+ type.should respond_to(:bar)
75
+ end
76
+ end
77
+
78
+ describe "auto-generated option setters" do
79
+ before do
80
+ @type.foo true
81
+ @type.bar 1
82
+ @property = @type.new(@model, @name, @options)
83
+ end
84
+
85
+ it "should set the pre-defined option values" do
86
+ @property.options[:foo].should == true
87
+ @property.options[:bar].should == 1
88
+ end
89
+
90
+ it "should ask the superclass for the value if unknown" do
91
+ @subtype.foo.should == true
92
+ @subtype.bar.should == 1
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ describe ".descendants" do
99
+ it "should include the sub-type" do
100
+ @type.descendants.include?(SubType).should be(true)
101
+ end
102
+ end
103
+
104
+ describe ".load_as" do
105
+ it "should return the load_as" do
106
+ [@type, @subtype].each do |type|
107
+ type.load_as.should be(@load_as)
108
+ end
109
+ end
110
+
111
+ it "should change the load_as class" do
112
+ @subtype.load_as Object
113
+ @subtype.load_as.should be(Object)
114
+ end
115
+ end
116
+ end
117
+
118
+ [:allow_blank, :allow_nil].each do |opt|
119
+ describe "##{method = "#{opt}?"}" do
120
+ [true, false].each do |value|
121
+ describe "when created with :#{opt} => #{value}" do
122
+ before do
123
+ @property = @type.new(@model, @name, @options.merge(opt => value))
124
+ end
125
+
126
+ it "should return #{value}" do
127
+ @property.send(method).should be(value)
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "when created with :#{opt} => true and :required => true" do
133
+ it "should fail with ArgumentError" do
134
+ lambda {
135
+ @property = @type.new(@model, @name, @options.merge(opt => true, :required => true))
136
+ }.should raise_error(ArgumentError,
137
+ "options[:required] cannot be mixed with :allow_nil or :allow_blank")
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ [:key?, :required?, :index, :unique_index, :unique?].each do |method|
144
+ describe "##{method}" do
145
+ [true, false].each do |value|
146
+ describe "when created with :#{method} => #{value}" do
147
+ before do
148
+ opt = method.to_s.chomp('?').to_sym
149
+ @property = @type.new(@model, @name, @options.merge(opt => value))
150
+ end
151
+
152
+ it "should return #{value}" do
153
+ @property.send(method).should be(value)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "#lazy?" do
161
+ describe "when created with :lazy => true, :key => false" do
162
+ before do
163
+ @property = @type.new(@model, @name, @options.merge(:lazy => true, :key => false))
164
+ end
165
+
166
+ it "should return true" do
167
+ @property.lazy?.should be(true)
168
+ end
169
+ end
170
+
171
+ describe "when created with :lazy => true, :key => true" do
172
+ before do
173
+ @property = @type.new(@model, @name, @options.merge(:lazy => true, :key => true))
174
+ end
175
+
176
+ it "should return false" do
177
+ @property.lazy?.should be(false)
178
+ end
179
+ end
180
+ end
181
+
182
+ describe '#instance_of?' do
183
+ subject { property.instance_of?(klass) }
184
+
185
+ let(:property) { @type.new(@model, @name, @options) }
186
+
187
+ context 'when provided the property class' do
188
+ let(:klass) { @type }
189
+
190
+ it { should be(true) }
191
+ end
192
+
193
+ context 'when provided the property superclass' do
194
+ let(:klass) { @type.superclass }
195
+
196
+ it { should be(false) }
197
+ end
198
+
199
+ context 'when provided the Ardm::Property class' do
200
+ let(:klass) { Ardm::Property }
201
+
202
+ it { should be(false) }
203
+ end
204
+ end
205
+
206
+ describe '#kind_of?' do
207
+ subject { property.kind_of?(klass) }
208
+
209
+ let(:property) { @type.new(@model, @name, @options) }
210
+
211
+ context 'when provided the property class' do
212
+ let(:klass) { @type }
213
+
214
+ it { should be(true) }
215
+ end
216
+
217
+ context 'when provided the property superclass' do
218
+ let(:klass) { @type.superclass }
219
+
220
+ it { should be(true) }
221
+ end
222
+
223
+ context 'when provided the Ardm::Property class' do
224
+ let(:klass) { Ardm::Property }
225
+
226
+ it { should be(true) }
227
+ end
228
+ end
229
+ end