mongomodel 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 (108) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +34 -0
  3. data/Rakefile +47 -0
  4. data/bin/console +45 -0
  5. data/lib/mongomodel.rb +92 -0
  6. data/lib/mongomodel/attributes/mongo.rb +40 -0
  7. data/lib/mongomodel/attributes/store.rb +30 -0
  8. data/lib/mongomodel/attributes/typecasting.rb +51 -0
  9. data/lib/mongomodel/concerns/abstract_class.rb +17 -0
  10. data/lib/mongomodel/concerns/activemodel.rb +11 -0
  11. data/lib/mongomodel/concerns/associations.rb +103 -0
  12. data/lib/mongomodel/concerns/associations/base/association.rb +33 -0
  13. data/lib/mongomodel/concerns/associations/base/definition.rb +56 -0
  14. data/lib/mongomodel/concerns/associations/base/proxy.rb +58 -0
  15. data/lib/mongomodel/concerns/associations/belongs_to.rb +68 -0
  16. data/lib/mongomodel/concerns/associations/has_many_by_foreign_key.rb +159 -0
  17. data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +175 -0
  18. data/lib/mongomodel/concerns/attribute_methods.rb +55 -0
  19. data/lib/mongomodel/concerns/attribute_methods/before_type_cast.rb +29 -0
  20. data/lib/mongomodel/concerns/attribute_methods/dirty.rb +35 -0
  21. data/lib/mongomodel/concerns/attribute_methods/protected.rb +127 -0
  22. data/lib/mongomodel/concerns/attribute_methods/query.rb +22 -0
  23. data/lib/mongomodel/concerns/attribute_methods/read.rb +29 -0
  24. data/lib/mongomodel/concerns/attribute_methods/write.rb +29 -0
  25. data/lib/mongomodel/concerns/attributes.rb +85 -0
  26. data/lib/mongomodel/concerns/callbacks.rb +294 -0
  27. data/lib/mongomodel/concerns/logging.rb +15 -0
  28. data/lib/mongomodel/concerns/pretty_inspect.rb +29 -0
  29. data/lib/mongomodel/concerns/properties.rb +69 -0
  30. data/lib/mongomodel/concerns/record_status.rb +42 -0
  31. data/lib/mongomodel/concerns/timestamps.rb +32 -0
  32. data/lib/mongomodel/concerns/validations.rb +38 -0
  33. data/lib/mongomodel/concerns/validations/associated.rb +46 -0
  34. data/lib/mongomodel/document.rb +20 -0
  35. data/lib/mongomodel/document/callbacks.rb +46 -0
  36. data/lib/mongomodel/document/dynamic_finders.rb +88 -0
  37. data/lib/mongomodel/document/finders.rb +82 -0
  38. data/lib/mongomodel/document/indexes.rb +91 -0
  39. data/lib/mongomodel/document/optimistic_locking.rb +48 -0
  40. data/lib/mongomodel/document/persistence.rb +143 -0
  41. data/lib/mongomodel/document/scopes.rb +161 -0
  42. data/lib/mongomodel/document/validations.rb +68 -0
  43. data/lib/mongomodel/document/validations/uniqueness.rb +78 -0
  44. data/lib/mongomodel/embedded_document.rb +42 -0
  45. data/lib/mongomodel/locale/en.yml +55 -0
  46. data/lib/mongomodel/support/collection.rb +109 -0
  47. data/lib/mongomodel/support/configuration.rb +35 -0
  48. data/lib/mongomodel/support/core_extensions.rb +10 -0
  49. data/lib/mongomodel/support/exceptions.rb +25 -0
  50. data/lib/mongomodel/support/mongo_options.rb +177 -0
  51. data/lib/mongomodel/support/types.rb +35 -0
  52. data/lib/mongomodel/support/types/array.rb +11 -0
  53. data/lib/mongomodel/support/types/boolean.rb +25 -0
  54. data/lib/mongomodel/support/types/custom.rb +38 -0
  55. data/lib/mongomodel/support/types/date.rb +20 -0
  56. data/lib/mongomodel/support/types/float.rb +13 -0
  57. data/lib/mongomodel/support/types/hash.rb +18 -0
  58. data/lib/mongomodel/support/types/integer.rb +13 -0
  59. data/lib/mongomodel/support/types/object.rb +21 -0
  60. data/lib/mongomodel/support/types/string.rb +9 -0
  61. data/lib/mongomodel/support/types/symbol.rb +9 -0
  62. data/lib/mongomodel/support/types/time.rb +12 -0
  63. data/lib/mongomodel/version.rb +3 -0
  64. data/spec/mongomodel/attributes/store_spec.rb +273 -0
  65. data/spec/mongomodel/concerns/activemodel_spec.rb +61 -0
  66. data/spec/mongomodel/concerns/associations/belongs_to_spec.rb +153 -0
  67. data/spec/mongomodel/concerns/associations/has_many_by_foreign_key_spec.rb +165 -0
  68. data/spec/mongomodel/concerns/associations/has_many_by_ids_spec.rb +192 -0
  69. data/spec/mongomodel/concerns/attribute_methods/before_type_cast_spec.rb +46 -0
  70. data/spec/mongomodel/concerns/attribute_methods/dirty_spec.rb +131 -0
  71. data/spec/mongomodel/concerns/attribute_methods/protected_spec.rb +86 -0
  72. data/spec/mongomodel/concerns/attribute_methods/query_spec.rb +27 -0
  73. data/spec/mongomodel/concerns/attribute_methods/read_spec.rb +52 -0
  74. data/spec/mongomodel/concerns/attribute_methods/write_spec.rb +43 -0
  75. data/spec/mongomodel/concerns/attributes_spec.rb +152 -0
  76. data/spec/mongomodel/concerns/callbacks_spec.rb +90 -0
  77. data/spec/mongomodel/concerns/logging_spec.rb +20 -0
  78. data/spec/mongomodel/concerns/pretty_inspect_spec.rb +68 -0
  79. data/spec/mongomodel/concerns/properties_spec.rb +29 -0
  80. data/spec/mongomodel/concerns/timestamps_spec.rb +170 -0
  81. data/spec/mongomodel/concerns/validations_spec.rb +159 -0
  82. data/spec/mongomodel/document/callbacks_spec.rb +80 -0
  83. data/spec/mongomodel/document/dynamic_finders_spec.rb +183 -0
  84. data/spec/mongomodel/document/finders_spec.rb +231 -0
  85. data/spec/mongomodel/document/indexes_spec.rb +121 -0
  86. data/spec/mongomodel/document/optimistic_locking_spec.rb +57 -0
  87. data/spec/mongomodel/document/persistence_spec.rb +319 -0
  88. data/spec/mongomodel/document/scopes_spec.rb +204 -0
  89. data/spec/mongomodel/document/validations/uniqueness_spec.rb +217 -0
  90. data/spec/mongomodel/document/validations_spec.rb +132 -0
  91. data/spec/mongomodel/document_spec.rb +74 -0
  92. data/spec/mongomodel/embedded_document_spec.rb +66 -0
  93. data/spec/mongomodel/mongomodel_spec.rb +33 -0
  94. data/spec/mongomodel/support/collection_spec.rb +248 -0
  95. data/spec/mongomodel/support/mongo_options_spec.rb +295 -0
  96. data/spec/mongomodel/support/property_spec.rb +83 -0
  97. data/spec/spec.opts +6 -0
  98. data/spec/spec_helper.rb +21 -0
  99. data/spec/specdoc.opts +6 -0
  100. data/spec/support/callbacks.rb +44 -0
  101. data/spec/support/helpers/define_class.rb +24 -0
  102. data/spec/support/helpers/specs_for.rb +11 -0
  103. data/spec/support/matchers/be_a_subclass_of.rb +5 -0
  104. data/spec/support/matchers/respond_to_boolean.rb +17 -0
  105. data/spec/support/matchers/run_callbacks.rb +20 -0
  106. data/spec/support/models.rb +23 -0
  107. data/spec/support/time.rb +6 -0
  108. metadata +232 -0
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ specs_for(Document, EmbeddedDocument) do
5
+ define_class(:TestDocument, described_class) do
6
+ property :foo, Date
7
+ end
8
+
9
+ subject { TestDocument.new }
10
+
11
+ describe "#read_attribute_before_type_cast" do
12
+ context "with property" do
13
+ it "should return the attribute before type casting" do
14
+ subject.attributes[:foo] = 'some date'
15
+ subject.read_attribute_before_type_cast(:foo).should == 'some date'
16
+ end
17
+
18
+ it "should define a reader method" do
19
+ subject.attributes[:foo] = 'some date'
20
+ subject.foo_before_type_cast.should == 'some date'
21
+ end
22
+ end
23
+
24
+ context "no property" do
25
+ it "should return the attribute without type casting" do
26
+ subject.attributes[:bar] = 'set bar'
27
+ subject.read_attribute_before_type_cast(:bar).should == 'set bar'
28
+ end
29
+
30
+ it "should not define a reader method" do
31
+ lambda { subject.bar_before_type_cast }.should raise_error(NoMethodError)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#attributes_before_type_cast" do
37
+ it "should return a hash of attributes before type casting" do
38
+ subject.attributes[:foo] = 'some date'
39
+ subject.attributes[:bar] = 'set bar'
40
+
41
+ subject.attributes_before_type_cast[:foo].should == 'some date'
42
+ subject.attributes_before_type_cast[:bar].should == 'set bar'
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ specs_for(Document, EmbeddedDocument) do
5
+ if specing?(Document)
6
+ define_class(:TestDocument, Document) do
7
+ property :foo, String
8
+ property :bar, String
9
+ end
10
+
11
+ subject { TestDocument.create!(:foo => 'original foo') }
12
+ else
13
+ define_class(:ChildDocument, EmbeddedDocument) do
14
+ property :foo, String
15
+ property :bar, String
16
+ end
17
+
18
+ define_class(:ParentDocument, Document) do
19
+ property :child, ChildDocument
20
+ end
21
+
22
+ let(:child) { ChildDocument.new(:foo => 'original foo') }
23
+ let(:parent) { ParentDocument.create!(:child => child) }
24
+
25
+ subject { parent.child }
26
+ end
27
+
28
+ describe "#write_attribute" do
29
+ before(:each) do
30
+ subject.write_attribute(:foo, 'new foo')
31
+ end
32
+
33
+ it "should add the old attribute name to the changed attributes" do
34
+ subject.changed.should include(:foo)
35
+ end
36
+
37
+ it "should not add other attributes to the changed attributes" do
38
+ subject.changed.should_not include(:bar)
39
+ end
40
+
41
+ it "should add the changed attribute value to the changes hash" do
42
+ subject.changes[:foo].should == ['original foo', 'new foo']
43
+ end
44
+
45
+ context "when called twice" do
46
+ before(:each) do
47
+ subject.write_attribute(:foo, 'new foo #2')
48
+ end
49
+
50
+ it "should keep the original value as the old value in the changes hash" do
51
+ subject.changes[:foo].should == ['original foo', 'new foo #2']
52
+ end
53
+ end
54
+ end
55
+
56
+ context "with changed attributes" do
57
+ context "attribute set to a new value" do
58
+ before(:each) do
59
+ subject.foo = 'foo changed'
60
+ end
61
+
62
+ it { should be_changed }
63
+ end
64
+
65
+ context "attribute set to the original value" do
66
+ before(:each) do
67
+ subject.foo = 'original foo'
68
+ end
69
+
70
+ it { should_not be_changed }
71
+ end
72
+ end
73
+
74
+ context "without changed attributes" do
75
+ it { should_not be_changed }
76
+ end
77
+
78
+ context "#original_attributes" do
79
+ context "with changes" do
80
+ before(:each) do
81
+ subject.foo = 'changed foo'
82
+ end
83
+
84
+ it "should return the attributes before changes" do
85
+ subject.original_attributes[:foo].should == 'original foo'
86
+ end
87
+ end
88
+
89
+ context "without changes" do
90
+ it "should return the attributes hash" do
91
+ subject.original_attributes.should == subject.attributes
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ specs_for(Document) do
98
+ define_class(:TestDocument, Document) do
99
+ property :foo, String
100
+ end
101
+
102
+ subject { TestDocument.create!(:foo => 'original foo') }
103
+
104
+ context "when saved" do
105
+ before(:each) do
106
+ subject.foo = 'changed foo'
107
+ end
108
+
109
+ context "with save" do
110
+ it "should reset the changed attributes" do
111
+ subject.save
112
+ subject.should_not be_changed
113
+ end
114
+ end
115
+
116
+ context "with save!" do
117
+ it "should reset the changed attributes" do
118
+ subject.save!
119
+ subject.should_not be_changed
120
+ end
121
+ end
122
+ end
123
+
124
+ context "when instantiated from database" do
125
+ it "should not be changed" do
126
+ instance = TestDocument.find(subject.id)
127
+ instance.should_not be_changed
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ specs_for(Document, EmbeddedDocument) do
5
+ define_class(:TestDocument, described_class) do
6
+ property :foo, String
7
+ property :bar, String
8
+ end
9
+
10
+ subject { TestDocument.new }
11
+
12
+ describe "#attr_protected" do
13
+ before(:each) do
14
+ TestDocument.attr_protected :foo
15
+ end
16
+
17
+ it "should disallow the attribute to be mass-assigned via attributes=" do
18
+ subject.attributes = { :foo => 'value of foo' }
19
+ subject.foo.should be_nil
20
+ end
21
+
22
+ it "should not disallow the attribute to be assigned individually" do
23
+ subject.foo = 'value of foo'
24
+ subject.foo.should == 'value of foo'
25
+ end
26
+
27
+ it "should not disallow other attributes to be mass-assigned via attributes=" do
28
+ subject.attributes = { :bar => 'value of bar' }
29
+ subject.bar.should == 'value of bar'
30
+ end
31
+
32
+ it "should accept multiple attributes" do
33
+ TestDocument.attr_protected :foo, :bar
34
+
35
+ subject.attributes = { :foo => 'value of foo', :bar => 'value of bar' }
36
+ subject.foo.should be_nil
37
+ subject.bar.should be_nil
38
+ end
39
+ end
40
+
41
+ describe "#attr_accessible" do
42
+ before(:each) do
43
+ TestDocument.attr_accessible :foo
44
+ end
45
+
46
+ it "should allow the attribute to be mass-assigned via attributes=" do
47
+ subject.attributes = { :foo => 'value of foo' }
48
+ subject.foo.should == 'value of foo'
49
+ end
50
+
51
+ it "should not disallow other attributes to be mass-assigned via attributes=" do
52
+ subject.attributes = { :bar => 'value of bar' }
53
+ subject.bar.should be_nil
54
+ end
55
+
56
+ it "should not disallow others attributes to be assigned individually" do
57
+ subject.bar = 'value of bar'
58
+ subject.bar.should == 'value of bar'
59
+ end
60
+
61
+ it "should accept multiple attributes" do
62
+ TestDocument.attr_accessible :foo, :bar
63
+
64
+ subject.attributes = { :foo => 'value of foo', :bar => 'value of bar' }
65
+ subject.foo.should == 'value of foo'
66
+ subject.bar.should == 'value of bar'
67
+ end
68
+ end
69
+
70
+ describe "#property" do
71
+ context "with :protected option" do
72
+ it "should make the attribute protected" do
73
+ TestDocument.should_receive(:attr_protected).with(:baz)
74
+ TestDocument.property :baz, String, :protected => true
75
+ end
76
+ end
77
+
78
+ context "with :accessible option" do
79
+ it "should make the attribute accessible" do
80
+ TestDocument.should_receive(:attr_accessible).with(:baz)
81
+ TestDocument.property :baz, String, :accessible => true
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ specs_for(Document, EmbeddedDocument) do
5
+ define_class(:TestDocument, described_class) do
6
+ property :foo, String
7
+ end
8
+
9
+ subject { TestDocument.new }
10
+
11
+ describe "#query_attribute" do
12
+ it "should return true if the attribute is not blank" do
13
+ subject.foo = 'set foo'
14
+ subject.query_attribute(:foo).should be_true
15
+ end
16
+
17
+ it "should return false if the attribute is blank" do
18
+ subject.foo = ''
19
+ subject.query_attribute(:foo).should be_false
20
+ end
21
+
22
+ it "should create a query method" do
23
+ subject.foo?.should == subject.query_attribute(:foo)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ specs_for(Document, EmbeddedDocument) do
5
+ define_class(:TestDocument, described_class) do
6
+ property :foo, String
7
+ end
8
+
9
+ subject { TestDocument.new(:foo => 'value of foo', :bar => 'value of bar') }
10
+
11
+ describe "#read_attribute" do
12
+ context "valid property" do
13
+ it "should return the attribute value" do
14
+ subject.read_attribute(:foo).should == 'value of foo'
15
+ end
16
+
17
+ it "should define a reader method" do
18
+ subject.foo.should == 'value of foo'
19
+ end
20
+ end
21
+
22
+ context "no property" do
23
+ it "should return the attribute value" do
24
+ subject.read_attribute(:bar).should == 'value of bar'
25
+ end
26
+
27
+ it "should not define a reader method" do
28
+ lambda { subject.bar }.should raise_error(NoMethodError)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#[]" do
34
+ it "should read the given attribute" do
35
+ subject.should_receive(:read_attribute).with(:foo).and_return('value of foo')
36
+ subject[:foo].should == 'value of foo'
37
+ end
38
+ end
39
+ end
40
+
41
+ specs_for(Document) do
42
+ define_class(:TestDocument, Document)
43
+
44
+ subject { TestDocument.new }
45
+
46
+ describe "#id" do
47
+ it "should return id from attributes" do
48
+ subject.id.should == subject.attributes[:id]
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ specs_for(Document, EmbeddedDocument) do
5
+ define_class(:TestDocument, described_class) do
6
+ property :foo, String
7
+ end
8
+
9
+ subject { TestDocument.new }
10
+
11
+ describe "#write_attribute" do
12
+ context "with property" do
13
+ it "should set the attribute hash" do
14
+ subject.write_attribute(:foo, 'set foo')
15
+ subject.attributes[:foo].should == 'set foo'
16
+ end
17
+
18
+ it "should define a writer method" do
19
+ subject.foo = 'set foo'
20
+ subject.attributes[:foo].should == 'set foo'
21
+ end
22
+ end
23
+
24
+ context "no property" do
25
+ it "should set the attribute hash" do
26
+ subject.write_attribute(:bar, 'set bar')
27
+ subject.attributes[:bar].should == 'set bar'
28
+ end
29
+
30
+ it "should not define a writer method" do
31
+ lambda { subject.bar = 'set bar' }.should raise_error(NoMethodError)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#[]=" do
37
+ it "should write the given attribute" do
38
+ subject.should_receive(:write_attribute).with(:foo, 'value of foo')
39
+ subject[:foo] = 'value of foo'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+
4
+ module MongoModel
5
+ AttributeTypes = {
6
+ String => "my string",
7
+ Integer => 99,
8
+ Float => 45.123,
9
+ Symbol => :foobar,
10
+ Boolean => false,
11
+ Array => [ 1, 2, 3, "hello", :world, [99, 100] ],
12
+ Hash => { :rabbit => 'hat', 'hello' => 12345 }.with_indifferent_access,
13
+ Date => Date.today,
14
+ Time => Time.now,
15
+ CustomClass => CustomClass.new('hello')
16
+ }
17
+
18
+ specs_for(Document, EmbeddedDocument) do
19
+ define_class(:TestDocument, described_class)
20
+
21
+ it "should have an attributes store on the instance" do
22
+ doc = TestDocument.new
23
+ doc.attributes.should be_an_instance_of(MongoModel::Attributes::Store)
24
+ end
25
+
26
+ it "should convert to mongo representation" do
27
+ doc = TestDocument.new
28
+ doc.to_mongo.should == doc.attributes.to_mongo
29
+ end
30
+
31
+ AttributeTypes.each do |type, value|
32
+ describe "setting #{type} attributes" do
33
+ define_class(:TestDocument, described_class) do
34
+ property :test_property, type
35
+ end
36
+
37
+ if specing?(EmbeddedDocument)
38
+ define_class(:ParentDocument, Document) do
39
+ property :child, TestDocument
40
+ end
41
+
42
+ let(:parent) { ParentDocument.create!(:child => TestDocument.new(:test_property => value)) }
43
+ let(:child) { parent.child }
44
+ let(:reloaded) { ParentDocument.find(parent.id).child }
45
+
46
+ subject { child }
47
+ else
48
+ subject { TestDocument.create!(:test_property => value) }
49
+
50
+ let(:reloaded) { TestDocument.find(subject.id) }
51
+ end
52
+
53
+ it "should read the correct value from attributes" do
54
+ subject.test_property.should == value
55
+ end
56
+
57
+ it "should read the correct value after reloading" do
58
+ reloaded.test_property.should == subject.test_property
59
+ end
60
+ end
61
+ end
62
+
63
+ it "should have an attributes store" do
64
+ doc = TestDocument.new
65
+ doc.attributes.should be_an_instance_of(MongoModel::Attributes::Store)
66
+ end
67
+
68
+ it "should duplicate attributes when duplicating object" do
69
+ original = TestDocument.new
70
+ duplicate = original.dup
71
+
72
+ duplicate.attributes.should_not equal(original.attributes)
73
+ end
74
+
75
+ describe "initializing" do
76
+ define_class(:Person, EmbeddedDocument) do
77
+ property :name, String
78
+ property :age, Integer, :default => 21
79
+ end
80
+
81
+ it "should be initializable with attributes hash" do
82
+ doc = Person.new(:name => 'Fred', :age => 42)
83
+ doc.name.should == 'Fred'
84
+ doc.age.should == 42
85
+ end
86
+
87
+ it "should use default attributes when initializing with partial attributes hash" do
88
+ doc = Person.new(:name => 'Maurice')
89
+ doc.age.should == 21
90
+ end
91
+
92
+ it "should load from mongo representation" do
93
+ doc = Person.from_mongo({ 'name' => 'James', 'age' => 15 })
94
+ doc.name.should == 'James'
95
+ doc.age.should == 15
96
+ end
97
+ end
98
+
99
+ describe "setting attributes with hash" do
100
+ define_class(:TestDocument, described_class) do
101
+ property :test_property, String
102
+
103
+ def test_property=(value)
104
+ write_attribute(:test_property, 'set from method')
105
+ end
106
+ end
107
+
108
+ subject { TestDocument.new }
109
+
110
+ it "should call custom property methods" do
111
+ subject.attributes = { :test_property => 'property value' }
112
+ subject.test_property.should == 'set from method'
113
+ end
114
+
115
+ it "should use write_attribute if no such property" do
116
+ subject.attributes = { :non_property => 'property value' }
117
+ subject.read_attribute(:non_property).should == 'property value'
118
+ end
119
+ end
120
+
121
+ describe "#new" do
122
+ define_class(:TestDocument, described_class)
123
+
124
+ it "should yield the instance to a block if provided" do
125
+ block_called = false
126
+
127
+ TestDocument.new do |doc|
128
+ block_called = true
129
+ doc.should be_an_instance_of(TestDocument)
130
+ end
131
+
132
+ block_called.should be_true
133
+ end
134
+ end
135
+
136
+ context "a frozen instance" do
137
+ define_class(:TestDocument, described_class) do
138
+ property :test_property, String
139
+ end
140
+
141
+ subject { TestDocument.new(:test_property => 'Test') }
142
+
143
+ before(:each) { subject.freeze }
144
+
145
+ it { should be_frozen }
146
+
147
+ it "should not allow changes to the attributes hash" do
148
+ lambda { subject.attributes[:test_property] = 'Change' }.should raise_error
149
+ end
150
+ end
151
+ end
152
+ end