public
Description: Plug-and-play data persistence created for small Ruby web applications.
Homepage: http://stone.rubyforge.org
Clone URL: git://github.com/ndemonner/stone.git
Search Repo:
Add many-to-many relationships.

* Can be declared via has_and_belongs_to_many or habtm

* They are very inefficient right now (keeping whole objects in relational 
arrays), but will switch them to simply use ids later
ndemonner (author)
Sat Apr 19 14:44:31 -0700 2008
commit  29e763998a8a71e4ad5b1f78f5287647fb6a6ba9
tree    8bc4d0a92218fa46d9f0fc6b393b9184e6da53da
parent  b49931094fa2750c888763ef8a1de81ca7d2c4bf
...
24
25
26
27
 
28
29
30
...
42
43
44
 
 
 
45
46
47
48
...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
...
85
86
87
88
89
90
91
92
93
94
95
 
 
 
 
 
96
97
98
99
100
101
 
 
 
 
 
 
 
 
 
 
 
 
102
103
104
...
152
153
154
155
 
156
157
158
159
160
...
178
179
180
181
 
 
 
 
 
182
 
183
 
 
184
185
186
...
24
25
26
 
27
28
29
30
...
42
43
44
45
46
47
48
49
50
51
...
71
72
73
 
74
75
76
77
78
 
79
80
81
82
83
84
...
86
87
88
 
89
 
90
 
 
 
 
91
92
93
94
95
96
 
 
 
 
 
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
159
160
161
 
162
163
164
165
166
167
...
185
186
187
 
188
189
190
191
192
193
194
195
196
197
198
199
200
0
@@ -24,7 +24,7 @@
0
         base.send(:include, ::Validatable)
0
         
0
         # rspec breaks if its classes have their contructor overwritten
0
- unless base.to_s.downcase =~ /spec::example::examplegroup::subclass_\d/
0
+ unless base.to_s.downcase =~ /(spec::example::examplegroup::subclass_\d|blah)/
0
           # allow object to be created with a hash of attributes...
0
           # [] allows for obj[attribute] retrieval
0
           # to_s allows for stupid Rails to work
0
@@ -42,6 +42,9 @@
0
                   end
0
                 end
0
               end
0
+ @@fields[self.class.to_s.make_key].each do |f|
0
+ instance_variable_set("@"+f[:name].to_s,[]) if f[:klass] == Array
0
+ end
0
             end
0
             
0
             def to_s
0
0
@@ -68,13 +71,11 @@
0
     # +name+<String>::
0
     #
0
     def field(name, klass, arg = nil)
0
-
0
       if arg && arg[:unique] == true
0
         unique = true
0
       else
0
         unique = false
0
       end
0
-
0
       klass_sym = self.to_s.make_key
0
       unless @@fields[klass_sym]
0
         @@fields[klass_sym] = [{:name => name,
0
0
0
0
@@ -85,20 +86,26 @@
0
                                 :klass => klass,
0
                                 :unique => unique}
0
       end
0
-
0
       name = name.to_s
0
-
0
       # add accessor for given field
0
- self.class_eval <<-EOS, __FILE__, __LINE__
0
- def #{name}
0
- @#{name}
0
- end
0
+ unless klass == Array
0
+ self.class_eval <<-EOS, __FILE__, __LINE__
0
+ def #{name}
0
+ @#{name}
0
+ end
0
         
0
- def #{name}=(value)
0
- @#{name} = value
0
- end
0
- EOS
0
- end
0
+ def #{name}=(value)
0
+ @#{name} = value
0
+ end
0
+ EOS
0
+ else
0
+ self.class_eval <<-EOS, __FILE__, __LINE__
0
+ def #{name}
0
+ @#{name}
0
+ end
0
+ EOS
0
+ end
0
+ end # field
0
     
0
     def id=(value)
0
       @id = value
0
@@ -152,7 +159,7 @@
0
     # the resource of which this class has many
0
     def has_many(resource, *args)
0
       self.class_eval <<-EOS, __FILE__, __LINE__
0
- def #{resource.to_s}
0
+ def #{resource.to_s}
0
           #{resource.to_s.singularize.titlecase}.all("#{self.to_s.downcase}_id".to_sym.equals => self.id)
0
         end
0
       EOS
0
0
0
@@ -178,9 +185,16 @@
0
       EOS
0
     end
0
     
0
- # TODO: implement this
0
+ # Registers a many-to-many association using an array of +resource+
0
+ # ids.
0
+ # === Parameters
0
+ # +resource+::
0
+ # The resource of which this class belongs to and has many
0
     def has_and_belongs_to_many(resource, *args)
0
+ field resource, Array
0
     end
0
+
0
+ alias_method :habtm, :has_and_belongs_to_many
0
     
0
     # Returns the first object matching +conditions+, or the first object
0
     # if no conditions are specified
...
24
25
26
27
 
28
29
30
...
42
43
44
 
 
 
45
46
47
48
...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
...
85
86
87
88
89
90
91
92
93
94
95
 
 
 
 
 
96
97
98
99
100
101
 
 
 
 
 
 
 
 
 
 
 
 
102
103
104
...
152
153
154
155
 
156
157
158
159
160
...
178
179
180
181
 
 
 
 
 
182
 
183
 
 
184
185
186
...
24
25
26
 
27
28
29
30
...
42
43
44
45
46
47
48
49
50
51
...
71
72
73
 
74
75
76
77
78
 
79
80
81
82
83
84
...
86
87
88
 
89
 
90
 
 
 
 
91
92
93
94
95
96
 
 
 
 
 
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
159
160
161
 
162
163
164
165
166
167
...
185
186
187
 
188
189
190
191
192
193
194
195
196
197
198
199
200
0
@@ -24,7 +24,7 @@
0
         base.send(:include, ::Validatable)
0
         
0
         # rspec breaks if its classes have their contructor overwritten
0
- unless base.to_s.downcase =~ /spec::example::examplegroup::subclass_\d/
0
+ unless base.to_s.downcase =~ /(spec::example::examplegroup::subclass_\d|blah)/
0
           # allow object to be created with a hash of attributes...
0
           # [] allows for obj[attribute] retrieval
0
           # to_s allows for stupid Rails to work
0
@@ -42,6 +42,9 @@
0
                   end
0
                 end
0
               end
0
+ @@fields[self.class.to_s.make_key].each do |f|
0
+ instance_variable_set("@"+f[:name].to_s,[]) if f[:klass] == Array
0
+ end
0
             end
0
             
0
             def to_s
0
0
@@ -68,13 +71,11 @@
0
     # +name+<String>::
0
     #
0
     def field(name, klass, arg = nil)
0
-
0
       if arg && arg[:unique] == true
0
         unique = true
0
       else
0
         unique = false
0
       end
0
-
0
       klass_sym = self.to_s.make_key
0
       unless @@fields[klass_sym]
0
         @@fields[klass_sym] = [{:name => name,
0
0
0
0
@@ -85,20 +86,26 @@
0
                                 :klass => klass,
0
                                 :unique => unique}
0
       end
0
-
0
       name = name.to_s
0
-
0
       # add accessor for given field
0
- self.class_eval <<-EOS, __FILE__, __LINE__
0
- def #{name}
0
- @#{name}
0
- end
0
+ unless klass == Array
0
+ self.class_eval <<-EOS, __FILE__, __LINE__
0
+ def #{name}
0
+ @#{name}
0
+ end
0
         
0
- def #{name}=(value)
0
- @#{name} = value
0
- end
0
- EOS
0
- end
0
+ def #{name}=(value)
0
+ @#{name} = value
0
+ end
0
+ EOS
0
+ else
0
+ self.class_eval <<-EOS, __FILE__, __LINE__
0
+ def #{name}
0
+ @#{name}
0
+ end
0
+ EOS
0
+ end
0
+ end # field
0
     
0
     def id=(value)
0
       @id = value
0
@@ -152,7 +159,7 @@
0
     # the resource of which this class has many
0
     def has_many(resource, *args)
0
       self.class_eval <<-EOS, __FILE__, __LINE__
0
- def #{resource.to_s}
0
+ def #{resource.to_s}
0
           #{resource.to_s.singularize.titlecase}.all("#{self.to_s.downcase}_id".to_sym.equals => self.id)
0
         end
0
       EOS
0
0
0
@@ -178,9 +185,16 @@
0
       EOS
0
     end
0
     
0
- # TODO: implement this
0
+ # Registers a many-to-many association using an array of +resource+
0
+ # ids.
0
+ # === Parameters
0
+ # +resource+::
0
+ # The resource of which this class belongs to and has many
0
     def has_and_belongs_to_many(resource, *args)
0
+ field resource, Array
0
     end
0
+
0
+ alias_method :habtm, :has_and_belongs_to_many
0
     
0
     # Returns the first object matching +conditions+, or the first object
0
     # if no conditions are specified
...
13
14
15
 
16
17
18
...
13
14
15
16
17
18
19
0
@@ -13,6 +13,7 @@
0
   
0
   has_many :posts
0
   has_many :comments
0
+ habtm :groups
0
   
0
   def cap_name
0
     self.name = self.name.titlecase
...
137
138
139
140
 
141
142
143
...
194
195
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
198
199
...
137
138
139
 
140
141
142
143
...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
0
@@ -137,7 +137,7 @@
0
     @post.author.should be_instance_of(Author)
0
   end
0
   
0
- it "should retrieve children objects id has_many has been set" do
0
+ it "should retrieve children objects if has_many has been set" do
0
     @post = Post.new
0
     @post.title = "Stone is Awesome"
0
     @post.body = "Stone is awesome because..."
0
@@ -194,6 +194,26 @@
0
   
0
   it "should only accept :asc or :desc for ordering" do
0
     lambda {Author.all(:created_at.lt => DateTime.now>>1, :order => {:created_at => :cool})}.should raise_error
0
+ end
0
+
0
+ it "should work with many-to-many associations via habtm" do
0
+ author1 = Author.first
0
+ author2 = Author.all.last
0
+ group1 = Group.new(:name => "Group One")
0
+ group2 = Group.new(:name => "Group Two")
0
+ group1.save
0
+ group2.save
0
+
0
+ author1.groups << group1
0
+ author1.groups << group2
0
+ group1.authors << author1
0
+ group1.authors << author2
0
+
0
+ author1.save
0
+ group1.save
0
+
0
+ author1.groups.size.should == 2
0
+ group1.authors.size.should == 2
0
   end
0
 
0
 end
...
1
2
 
 
3
4
5
6
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
9
10
11
12
 
 
...
 
 
1
2
3
4
5
6
 
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
 
42
43
0
@@ -1,13 +1,44 @@
0
---- !ruby/object:Author
0
-created_at: 2008-04-18T17:08:59-07:00
0
+--- &id001 !ruby/object:Author
0
+created_at: 2008-04-19T14:42:31-07:00
0
 email: nick@cladby.com
0
 errors: !ruby/object:Validatable::Errors
0
   errors: {}
0
 
0
-favorite_number: 8
0
+favorite_number: 40
0
+groups:
0
+- !ruby/object:Group
0
+ authors:
0
+ - *id001
0
+ - !ruby/object:Author
0
+ created_at: 2008-04-19T14:42:31-07:00
0
+ email: chariot_guy@hotmail.com
0
+ errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+ favorite_number: 47
0
+ groups: []
0
+
0
+ id: 5
0
+ name: Ben Hurr
0
+ times_validated_hash:
0
+ Author/Validatable::ValidatesPresenceOf/email: 1
0
+ Author/Validatable::ValidatesPresenceOf/name: 1
0
+ errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+ id: 1
0
+ name: Group One
0
+- !ruby/object:Group
0
+ authors: []
0
+
0
+ errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+ id: 1
0
+ name: Group Two
0
 id: 1
0
 name: Nick DeMonner
0
 times_validated_hash:
0
- Author/Validatable::ValidatesPresenceOf/email: 4
0
- Author/Validatable::ValidatesPresenceOf/name: 4
0
+ Author/Validatable::ValidatesPresenceOf/email: 5
0
+ Author/Validatable::ValidatesPresenceOf/name: 5
...
1
2
 
3
4
5
6
7
 
 
 
8
9
10
...
1
 
2
3
4
5
6
 
7
8
9
10
11
12
0
@@ -1,10 +1,12 @@
0
 --- !ruby/object:Author
0
-created_at: 2008-04-18T17:08:59-07:00
0
+created_at: 2008-04-19T14:42:31-07:00
0
 email: heyo@something.com
0
 errors: !ruby/object:Validatable::Errors
0
   errors: {}
0
 
0
-favorite_number: 30
0
+favorite_number: 37
0
+groups: []
0
+
0
 id: 2
0
 name: Mike McMichaels
0
 times_validated_hash:
...
1
2
 
3
4
5
6
7
 
 
 
8
9
10
...
1
 
2
3
4
5
6
 
7
8
9
10
11
12
0
@@ -1,10 +1,12 @@
0
 --- !ruby/object:Author
0
-created_at: 2008-04-18T17:08:59-07:00
0
+created_at: 2008-04-19T14:42:31-07:00
0
 email: weyo@something.com
0
 errors: !ruby/object:Validatable::Errors
0
   errors: {}
0
 
0
-favorite_number: 12
0
+favorite_number: 46
0
+groups: []
0
+
0
 id: 3
0
 name: Mary Poppins
0
 times_validated_hash:
...
1
2
 
3
4
5
6
7
 
 
 
8
9
10
...
1
 
2
3
4
5
6
 
7
8
9
10
11
12
0
@@ -1,10 +1,12 @@
0
 --- !ruby/object:Author
0
-created_at: 2008-04-18T17:08:59-07:00
0
+created_at: 2008-04-19T14:42:31-07:00
0
 email: nick@gmail.com
0
 errors: !ruby/object:Validatable::Errors
0
   errors: {}
0
 
0
-favorite_number: 2
0
+favorite_number: 29
0
+groups: []
0
+
0
 id: 4
0
 name: Nick Hicklesby
0
 times_validated_hash:
...
1
2
 
3
4
5
6
7
 
 
 
8
9
10
...
1
 
2
3
4
5
6
 
7
8
9
10
11
12
0
@@ -1,10 +1,12 @@
0
 --- !ruby/object:Author
0
-created_at: 2008-04-18T17:08:59-07:00
0
+created_at: 2008-04-19T14:42:31-07:00
0
 email: chariot_guy@hotmail.com
0
 errors: !ruby/object:Validatable::Errors
0
   errors: {}
0
 
0
-favorite_number: 22
0
+favorite_number: 47
0
+groups: []
0
+
0
 id: 5
0
 name: Ben Hurr
0
 times_validated_hash:
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
0
@@ -1 +1,44 @@
0
+--- &id001 !ruby/object:Group
0
+authors:
0
+- !ruby/object:Author
0
+ created_at: 2008-04-19T14:42:31-07:00
0
+ email: nick@cladby.com
0
+ errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+ favorite_number: 40
0
+ groups:
0
+ - *id001
0
+ - !ruby/object:Group
0
+ authors: []
0
+
0
+ errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+ id: 1
0
+ name: Group Two
0
+ id: 1
0
+ name: Nick DeMonner
0
+ times_validated_hash:
0
+ Author/Validatable::ValidatesPresenceOf/email: 5
0
+ Author/Validatable::ValidatesPresenceOf/name: 5
0
+- !ruby/object:Author
0
+ created_at: 2008-04-19T14:42:31-07:00
0
+ email: chariot_guy@hotmail.com
0
+ errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+ favorite_number: 47
0
+ groups: []
0
+
0
+ id: 5
0
+ name: Ben Hurr
0
+ times_validated_hash:
0
+ Author/Validatable::ValidatesPresenceOf/email: 1
0
+ Author/Validatable::ValidatesPresenceOf/name: 1
0
+errors: !ruby/object:Validatable::Errors
0
+ errors: {}
0
+
0
+id: 1
0
+name: Group One
...
13
14
15
 
16
17
18
...
13
14
15
16
17
18
19
0
@@ -13,6 +13,7 @@
0
   
0
   has_many :posts
0
   has_many :comments
0
+ habtm :groups
0
   
0
   def cap_name
0
     self.name = self.name.titlecase
...
1
2
3
4
5
6
7
8
9
...
 
 
 
 
 
 
 
 
 
0
@@ -1,10 +1 @@
0
-class Comment #:nodoc:
0
- include Stone::Resource
0
-
0
- field :body, String
0
-
0
- belongs_to :post
0
- belongs_to :person
0
- belongs_to :author
0
-end
...
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
0
@@ -1 +1,10 @@
0
+class Group
0
+ include Stone::Resource
0
+
0
+ field :name, String
0
+ field :authors, Array
0
+
0
+ has_and_belongs_to_many :authors
0
+
0
+end
...
1
2
3
4
5
6
...
 
 
 
 
 
 
0
@@ -1,7 +1 @@
0
-class Person
0
- include Stone::Resource
0
-
0
- field :name, String
0
- has_many :comments
0
-end
...
137
138
139
140
 
141
142
143
...
194
195
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
198
199
...
137
138
139
 
140
141
142
143
...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
0
@@ -137,7 +137,7 @@
0
     @post.author.should be_instance_of(Author)
0
   end
0
   
0
- it "should retrieve children objects id has_many has been set" do
0
+ it "should retrieve children objects if has_many has been set" do
0
     @post = Post.new
0
     @post.title = "Stone is Awesome"
0
     @post.body = "Stone is awesome because..."
0
@@ -194,6 +194,26 @@
0
   
0
   it "should only accept :asc or :desc for ordering" do
0
     lambda {Author.all(:created_at.lt => DateTime.now>>1, :order => {:created_at => :cool})}.should raise_error
0
+ end
0
+
0
+ it "should work with many-to-many associations via habtm" do
0
+ author1 = Author.first
0
+ author2 = Author.all.last
0
+ group1 = Group.new(:name => "Group One")
0
+ group2 = Group.new(:name => "Group Two")
0
+ group1.save
0
+ group2.save
0
+
0
+ author1.groups << group1
0
+ author1.groups << group2
0
+ group1.authors << author1
0
+ group1.authors << author2
0
+
0
+ author1.save
0
+ group1.save
0
+
0
+ author1.groups.size.should == 2
0
+ group1.authors.size.should == 2
0
   end
0
 
0
 end

Comments

    No one has commented yet.