acts_as_eav_model 0.0.0

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 (80) hide show
  1. data/.rvmrc +1 -0
  2. data/CHANGELOG +3 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +92 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +117 -0
  7. data/Rakefile +46 -0
  8. data/SPECDOC +23 -0
  9. data/TODO +0 -0
  10. data/VERSION +1 -0
  11. data/doc/classes/ActiveRecord/Acts/EavModel.html +213 -0
  12. data/doc/classes/ActiveRecord/Acts/EavModel/ClassMethods.html +343 -0
  13. data/doc/classes/ActiveRecord/Acts/EavModel/InstanceMethods.html +474 -0
  14. data/doc/classes/ActiveRecord/Acts/EavModel/InstanceMethods/ClassMethods.html +192 -0
  15. data/doc/classes/ActiveRecord/Base.html +170 -0
  16. data/doc/created.rid +1 -0
  17. data/doc/files/CHANGELOG.html +113 -0
  18. data/doc/files/MIT-LICENSE.html +129 -0
  19. data/doc/files/README_rdoc.html +248 -0
  20. data/doc/files/SPECDOC.html +170 -0
  21. data/doc/files/lib/acts_as_eav_model_rb.html +101 -0
  22. data/doc/fr_class_index.html +31 -0
  23. data/doc/fr_file_index.html +31 -0
  24. data/doc/fr_method_index.html +40 -0
  25. data/doc/index.html +24 -0
  26. data/doc/rdoc-style.css +208 -0
  27. data/init.rb +1 -0
  28. data/install.rb +1 -0
  29. data/lib/acts_as_eav_model.rb +542 -0
  30. data/spec/dummy/Rakefile +7 -0
  31. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  32. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  33. data/spec/dummy/app/models/document.rb +7 -0
  34. data/spec/dummy/app/models/person.rb +13 -0
  35. data/spec/dummy/app/models/person_contact_info.rb +2 -0
  36. data/spec/dummy/app/models/post.rb +4 -0
  37. data/spec/dummy/app/models/post_attribute.rb +2 -0
  38. data/spec/dummy/app/models/preference.rb +5 -0
  39. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  40. data/spec/dummy/config.ru +4 -0
  41. data/spec/dummy/config/application.rb +45 -0
  42. data/spec/dummy/config/boot.rb +10 -0
  43. data/spec/dummy/config/database.yml +22 -0
  44. data/spec/dummy/config/environment.rb +5 -0
  45. data/spec/dummy/config/environments/development.rb +26 -0
  46. data/spec/dummy/config/environments/production.rb +49 -0
  47. data/spec/dummy/config/environments/test.rb +35 -0
  48. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/spec/dummy/config/initializers/inflections.rb +10 -0
  50. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  51. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  52. data/spec/dummy/config/initializers/session_store.rb +8 -0
  53. data/spec/dummy/config/locales/en.yml +5 -0
  54. data/spec/dummy/config/routes.rb +58 -0
  55. data/spec/dummy/db/development.sqlite3 +0 -0
  56. data/spec/dummy/db/schema.rb +51 -0
  57. data/spec/dummy/public/404.html +26 -0
  58. data/spec/dummy/public/422.html +26 -0
  59. data/spec/dummy/public/500.html +26 -0
  60. data/spec/dummy/public/favicon.ico +0 -0
  61. data/spec/dummy/public/javascripts/application.js +2 -0
  62. data/spec/dummy/public/javascripts/controls.js +965 -0
  63. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  64. data/spec/dummy/public/javascripts/effects.js +1123 -0
  65. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  66. data/spec/dummy/public/javascripts/rails.js +175 -0
  67. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  68. data/spec/dummy/script/rails +6 -0
  69. data/spec/fixtures/people.yml +4 -0
  70. data/spec/fixtures/person_contact_infos.yml +10 -0
  71. data/spec/fixtures/post_attributes.yml +15 -0
  72. data/spec/fixtures/posts.yml +9 -0
  73. data/spec/fixtures/preferences.yml +10 -0
  74. data/spec/models/eav_model_with_no_arguments_spec.rb +82 -0
  75. data/spec/models/eav_model_with_options_spec.rb +37 -0
  76. data/spec/models/eav_validation_spec.rb +11 -0
  77. data/spec/schema.rb +50 -0
  78. data/spec/spec_helper.rb +38 -0
  79. data/uninstall.rb +1 -0
  80. metadata +213 -0
@@ -0,0 +1,129 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: MIT-LICENSE</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>MIT-LICENSE</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>MIT-LICENSE
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Thu Dec 18 13:10:57 +1300 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <p>
73
+ Copyright (c) 2008 Marcus Wyatt
74
+ </p>
75
+ <p>
76
+ Permission is hereby granted, free of charge, to any person obtaining a
77
+ copy of this software and associated documentation files (the
78
+ &quot;Software&quot;), to deal in the Software without restriction,
79
+ including without limitation the rights to use, copy, modify, merge,
80
+ publish, distribute, sublicense, and/or sell copies of the Software, and to
81
+ permit persons to whom the Software is furnished to do so, subject to the
82
+ following conditions:
83
+ </p>
84
+ <p>
85
+ The above copyright notice and this permission notice shall be included in
86
+ all copies or substantial portions of the Software.
87
+ </p>
88
+ <p>
89
+ THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
90
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
91
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
92
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
93
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
94
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
95
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
96
+ </p>
97
+
98
+ </div>
99
+
100
+
101
+ </div>
102
+
103
+
104
+ </div>
105
+
106
+
107
+ <!-- if includes -->
108
+
109
+ <div id="section">
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+ <!-- if method_list -->
119
+
120
+
121
+ </div>
122
+
123
+
124
+ <div id="validator-badges">
125
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
126
+ </div>
127
+
128
+ </body>
129
+ </html>
@@ -0,0 +1,248 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: README.rdoc</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>README.rdoc</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>README.rdoc
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Thu Dec 18 11:13:37 +1300 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <p>
73
+ ActsAsEavModel
74
+ </p>
75
+ <h6>========</h6>
76
+ <p>
77
+ ActsAsEavModel allow for the Entity-attribute-value model (EAV), also known
78
+ as object-attribute-value model and open schema on any of your ActiveRecord
79
+ models.
80
+ </p>
81
+ <h1>What is Entity-attribute-value model?</h1>
82
+ <p>
83
+ Entity-attribute-value model (EAV) is a data model that is used in
84
+ circumstances where the number of attributes (properties, parameters) that
85
+ can be used to describe a thing (an &quot;entity&quot; or
86
+ &quot;object&quot;) is potentially very vast, but the number that will
87
+ actually apply to a given entity is relatively modest.
88
+ </p>
89
+ <h1>Typical Problem</h1>
90
+ <p>
91
+ A good example of this is where you need to store lots (possible hundreds)
92
+ of optional attributes on an object. My typical reference example is when
93
+ you have a User object. You want to store the user&#8216;s preferences
94
+ between sessions. Every search, sort, etc in your application you want to
95
+ keep track of so when the user visits that section of the application again
96
+ you can simply restore the display to how it was.
97
+ </p>
98
+ <p>
99
+ So your controller might have:
100
+ </p>
101
+ <pre>
102
+ Project.find :all, :conditions =&gt; current_user.project_search,
103
+ :order =&gt; current_user.project_order
104
+ </pre>
105
+ <p>
106
+ But there could be hundreds of these little attributes that you really
107
+ don&#8216;t want to store directly on the user object. It would make your
108
+ table have too many columns so it would be too much of a pain to deal with.
109
+ Also there might be performance problems. So instead you might do something
110
+ like this:
111
+ </p>
112
+ <pre>
113
+ class User &lt; ActiveRecord::Base
114
+ has_many :preferences
115
+ end
116
+
117
+ class Preferences &lt; ActiveRecord::Base
118
+ belongs_to :user
119
+ end
120
+ </pre>
121
+ <p>
122
+ Now simply give the Preference model a &quot;name&quot; and
123
+ &quot;value&quot; column and you are set.&#8230;. except this is now too
124
+ complicated. To retrieve a attribute you will need to do something like:
125
+ </p>
126
+ <pre>
127
+ Project.find :all,
128
+ :conditions =&gt; current_user.preferences.find_by_name('project_search').value,
129
+ :order =&gt; current_user.preferences.find_by_name('project_order').value
130
+ </pre>
131
+ <p>
132
+ Sure you could fix this through a few methods on your model. But what about
133
+ saving?
134
+ </p>
135
+ <pre>
136
+ current_user.preferences.create :name =&gt; 'project_search',
137
+ :value =&gt; &quot;lastname LIKE 'jones%'&quot;
138
+ current_user.preferences.create :name =&gt; 'project_order',
139
+ :value =&gt; &quot;name&quot;
140
+ </pre>
141
+ <p>
142
+ Again this seems to much. Again we could add some methods to our model to
143
+ make this simpler but do we want to do this on every model. NO! So instead
144
+ we use this plugin which does everything for us.
145
+ </p>
146
+ <h1>Capabilities</h1>
147
+ <p>
148
+ The ActsAsEavModel plugin is capable of modeling this problem in a
149
+ intuitive way. Instead of having to deal with a related model you treat all
150
+ attributes (both on the model and related) as if they are all on the model.
151
+ The plugin will try to save all attributes to the model (normal
152
+ ActiveRecord behavior) but if there is no column for an attribute it will
153
+ try to save it to a related model whose purpose is to store these many
154
+ sparsely populated attributes.
155
+ </p>
156
+ <p>
157
+ The main design goals are:
158
+ </p>
159
+ <ul>
160
+ <li>Have the eav attributes feel like normal attributes. Simple gets and sets
161
+ will add and remove records from the related model.
162
+
163
+ </li>
164
+ <li>Allow for more than one related model. So for example on my User model I
165
+ might have some eav behavior going into a contact_info table while others
166
+ are going in a user_preferences table.
167
+
168
+ </li>
169
+ <li>Allow a model to determine what a valid eav attribute is for a given
170
+ related model so our model still can generate a NoMethodError.
171
+
172
+ </li>
173
+ </ul>
174
+ <p>
175
+ Example
176
+ </p>
177
+ <h6>=</h6>
178
+ <p>
179
+ Will make the current class have eav behaviour.
180
+ </p>
181
+ <pre>
182
+ class Post &lt; ActiveRecord::Base
183
+ has_eav_behavior
184
+ end
185
+ post = Post.find_by_title 'hello world'
186
+ puts &quot;My post intro is: #{post.intro}&quot;
187
+ post.teaser = 'An awesome introduction to the blog'
188
+ post.save
189
+ </pre>
190
+ <p>
191
+ The above example should work even though &quot;intro&quot; and
192
+ &quot;teaser&quot; are not attributes on the Post model.
193
+ </p>
194
+ <h1>Installation</h1>
195
+ <pre>
196
+ ./script/plugin install acts_as_eav_model
197
+ </pre>
198
+ <h1>RUNNING UNIT TESTS</h1>
199
+ <h2>Creating the test database</h2>
200
+ <p>
201
+ The test databases will be created from the info specified in
202
+ test/database.yml. Either change that file to match your database or change
203
+ your database to match that file.
204
+ </p>
205
+ <h2>Running with Rake</h2>
206
+ <p>
207
+ The easiest way to run the unit tests is through Rake. By default sqlite3
208
+ will be the database run. Just change your env variable DB to be the
209
+ database adaptor (specified in database.yml) that you want to use. The
210
+ database and permissions must already be setup but the tables will be
211
+ created for you from schema.rb.
212
+ </p>
213
+ <p>
214
+ Copyright (c) 2008 Marcus Wyatt, released under the MIT license
215
+ </p>
216
+
217
+ </div>
218
+
219
+
220
+ </div>
221
+
222
+
223
+ </div>
224
+
225
+
226
+ <!-- if includes -->
227
+
228
+ <div id="section">
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+ <!-- if method_list -->
238
+
239
+
240
+ </div>
241
+
242
+
243
+ <div id="validator-badges">
244
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
245
+ </div>
246
+
247
+ </body>
248
+ </html>
@@ -0,0 +1,170 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: SPECDOC</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>SPECDOC</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>SPECDOC
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Thu Dec 18 13:47:02 +1300 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <p>
73
+ ActiveRecord Model annotated with &#8216;has_eav_behavior&#8217; with no
74
+ options in declaration
75
+ </p>
76
+ <ul>
77
+ <li>should have many attributes
78
+
79
+ </li>
80
+ <li>should create new attribute on save
81
+
82
+ </li>
83
+ <li>should delete attribute
84
+
85
+ </li>
86
+ <li>should write eav attributes to attributes table
87
+
88
+ </li>
89
+ <li>should return nil when attribute does not exist
90
+
91
+ </li>
92
+ <li>should use method missing to make attribute seem as native property
93
+
94
+ </li>
95
+ <li>should read attributes using subscript notation
96
+
97
+ </li>
98
+ <li>should read the attribute when invoking &#8216;read_attribute&#8216;
99
+
100
+ </li>
101
+ </ul>
102
+ <p>
103
+ ActiveRecord Model annotated with &#8216;has_eav_behavior&#8217; with
104
+ options in declaration
105
+ </p>
106
+ <ul>
107
+ <li>should be &#8216;has_many&#8217; association on both sides
108
+
109
+ </li>
110
+ <li>should only allow restricted fields when specified (:fields =&gt; %w(phone
111
+ aim icq))
112
+
113
+ </li>
114
+ <li>should raise &#8216;NoMethodError&#8217; when attribute not in
115
+ &#8216;eav_attributes&#8217; method array
116
+
117
+ </li>
118
+ <li>should raise &#8216;NoMethodError&#8217; when attribute does not satisfy
119
+ &#8216;is_eav_attribute?&#8217; method
120
+
121
+ </li>
122
+ </ul>
123
+ <p>
124
+ Validations on ActiveRecord Model annotated with
125
+ &#8216;has_eav_behavior&#8216;
126
+ </p>
127
+ <ul>
128
+ <li>should execute as normal (validates_presence_of)
129
+
130
+ </li>
131
+ </ul>
132
+ <p>
133
+ Finished in 0.239663 seconds
134
+ </p>
135
+ <p>
136
+ 13 examples, 0 failures
137
+ </p>
138
+
139
+ </div>
140
+
141
+
142
+ </div>
143
+
144
+
145
+ </div>
146
+
147
+
148
+ <!-- if includes -->
149
+
150
+ <div id="section">
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+ <!-- if method_list -->
160
+
161
+
162
+ </div>
163
+
164
+
165
+ <div id="validator-badges">
166
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
167
+ </div>
168
+
169
+ </body>
170
+ </html>