eav_hashes 1.0.1 → 1.0.2

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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -20
  3. data/README.md +147 -147
  4. data/Rakefile +30 -30
  5. data/lib/eav_hashes/activerecord_extension.rb +37 -37
  6. data/lib/eav_hashes/eav_entry.rb +128 -128
  7. data/lib/eav_hashes/eav_hash.rb +167 -167
  8. data/lib/eav_hashes/util.rb +122 -122
  9. data/lib/eav_hashes/version.rb +5 -5
  10. data/lib/eav_hashes.rb +8 -8
  11. data/lib/generators/eav_migration/USAGE +26 -26
  12. data/lib/generators/eav_migration/eav_migration.rb +35 -35
  13. data/lib/generators/eav_migration/templates/eav_migration.erb +15 -15
  14. data/spec/dummy/README.rdoc +261 -261
  15. data/spec/dummy/Rakefile +7 -7
  16. data/spec/dummy/app/assets/javascripts/application.js +15 -15
  17. data/spec/dummy/app/assets/stylesheets/application.css +13 -13
  18. data/spec/dummy/app/controllers/application_controller.rb +3 -3
  19. data/spec/dummy/app/helpers/application_helper.rb +2 -2
  20. data/spec/dummy/app/models/custom_test_object.rb +6 -6
  21. data/spec/dummy/app/models/product.rb +3 -4
  22. data/spec/dummy/app/views/layouts/application.html.erb +14 -14
  23. data/spec/dummy/config/application.rb +62 -68
  24. data/spec/dummy/config/boot.rb +9 -9
  25. data/spec/dummy/config/database.yml +25 -25
  26. data/spec/dummy/config/environment.rb +5 -5
  27. data/spec/dummy/config/environments/development.rb +34 -37
  28. data/spec/dummy/config/environments/production.rb +70 -67
  29. data/spec/dummy/config/environments/test.rb +34 -37
  30. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -7
  31. data/spec/dummy/config/initializers/inflections.rb +15 -15
  32. data/spec/dummy/config/initializers/mime_types.rb +5 -5
  33. data/spec/dummy/config/initializers/secret_token.rb +7 -7
  34. data/spec/dummy/config/initializers/session_store.rb +8 -8
  35. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
  36. data/spec/dummy/config/locales/en.yml +5 -5
  37. data/spec/dummy/config/routes.rb +58 -58
  38. data/spec/dummy/config.ru +4 -4
  39. data/spec/dummy/db/migrate/20121206133059_create_products.rb +9 -9
  40. data/spec/dummy/db/migrate/20121210055854_create_product_tech_specs.rb +15 -15
  41. data/spec/dummy/db/seeds.rb +30 -30
  42. data/spec/dummy/public/404.html +26 -26
  43. data/spec/dummy/public/422.html +26 -26
  44. data/spec/dummy/public/500.html +25 -25
  45. data/spec/dummy/script/rails +6 -6
  46. data/spec/lib/eav_hashes/eav_hash_spec.rb +147 -137
  47. data/spec/lib/generators/eav_migration_spec.rb +60 -60
  48. data/spec/spec_helper.rb +24 -24
  49. metadata +25 -44
  50. data/spec/dummy/db/development.sqlite3 +0 -0
  51. data/spec/dummy/db/schema.rb +0 -35
  52. data/spec/dummy/db/test.sqlite3 +0 -0
  53. data/spec/dummy/log/ENV=test.log +0 -1
  54. data/spec/dummy/log/development.log +0 -46
  55. data/spec/dummy/log/test.log +0 -4623
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ae80ab5c3269d2d2d014229a916e6bd2d1f5887a
4
+ data.tar.gz: 5e90a1d6874451e1cf34ccfd88bce14e459b274d
5
+ SHA512:
6
+ metadata.gz: 160c12fd33afa959a6597fa45c3e0d3edfa663d8fa7c33037fb0131e791180829dbc1c2fe1a43f8927a3f22e3e51cc6776bec16c0204e320513080677c03027d
7
+ data.tar.gz: bbd73843daaad8e0668a3ee1eba60eaabb20e80490bfe0d86203303b08ca4e44bb7d66720d4d67c7e3657acdb0bb57bad063b21d037fd928931f4cd9d9501075
data/MIT-LICENSE CHANGED
@@ -1,20 +1,20 @@
1
- Copyright 2012 Ilya Ostrovskiy
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright 2012 Ilya Ostrovskiy
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,147 +1,147 @@
1
- eav_hashes
2
- =========
3
-
4
- [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/200proof/eav_hashes) [![Build Status](https://travis-ci.org/200proof/eav_hashes.png?branch=master)](https://travis-ci.org/200proof/eav_hashes)
5
-
6
- `eav_hashes` is a neato gem for implementing the EAV (entity-attribute-value)
7
- database design pattern in your Rails models. All you need to do is add one
8
- line to your model's code and that's it! Schema generation is automatically
9
- handled for you.
10
-
11
- Why would I need it?
12
- -
13
- Rails' ActiveRecord includes a helper function, `serialize`, to allow you to
14
- save complex data types (like hashes) into your database. Unfortunately, it
15
- isn't very useful. A lot of overhead is created from serialization and
16
- deserialization, and you can't search by the contents of your hash. That's
17
- where `eav_hashes` comes in.
18
-
19
- How does it work?
20
- -
21
- Great question! Lets dive in with a simple code example, but first lets set up the gem.
22
-
23
- Put this in your gemfile...
24
-
25
- gem "eav_hashes", "~> 1.0.0"
26
-
27
- ...and update your bundle.
28
-
29
- $ bundle install
30
-
31
-
32
- Now, lets make this Rails model.
33
-
34
- ```ruby
35
- class Product < ActiveRecord::Base
36
- eav_hash_for :tech_specs
37
- end
38
- ```
39
-
40
- Now run this generator to create a migration:
41
-
42
- $ rails generate eav_migration Product tech_specs
43
-
44
- And run the migration:
45
-
46
- $ rake db:migrate
47
-
48
- Now watch the magic the happen:
49
-
50
- ```ruby
51
- # Assuming this whole example is on a blank DB, of course
52
- a_product = Product.new
53
- a_product.tech_specs["Widget Power"] = "1.21 GW"
54
- a_product.tech_specs["Battery Life (hours)"] = 12
55
- a_product.tech_specs["Warranty (years)"] = 3.5
56
- a_product.tech_specs["RoHS Compliant"] = true
57
- a_product.save!
58
-
59
- # Setting a value to nil deletes the entry
60
- a_product.tech_specs["Warranty (years)"] = nil
61
- a_product.save!
62
-
63
- the_same_product = Product.first
64
- puts the_same_product.tech_specs["nonexistant key"]
65
-
66
- # magic alert: this actually gets the count of EVERY entry of every
67
- # hash for this model, but for this example this works
68
- puts "Entry Count: #{ProductTechSpecsEntry.count}"
69
- the_same_product.tech_specs.each_pair do |key, value|
70
- puts "#{key}: #{value.to_s}"
71
- end
72
-
73
- # Ruby's default types: Integer, Float, Complex, Rational, Symbol,
74
- # TrueClass, and FalseClass are preserved between transactions like
75
- # you would expect them to.
76
- puts the_same_product.tech_specs["Battery Life (hours)"]+3
77
- ```
78
-
79
- And the output, as you can expect, will be along the lines of:
80
-
81
- nil
82
- Entry Count: 3
83
- Widget Power: 1.21 GW
84
- Battery Life (hours): 12
85
- RoHS Compliant: true
86
- 15
87
-
88
-
89
- That looks incredibly simple, right? Good! It's supposed to be! All the magic
90
- happens when you call `save!`.
91
-
92
- Now you could start doing other cool stuff, like searching for products based
93
- on their tech specs! You've already figured out how to do this, haven't you?
94
-
95
- ```ruby
96
- flux_capacitor = Product.find_by_tech_specs("Widget Power", "1.21 GW")
97
- ```
98
-
99
- Nifty, right?
100
-
101
- Can I store arrays/hashes/custom types inside my hashes?
102
- --
103
- Sure, but they'll be serialized into YAML (so you cant search by them like you
104
- would an eav_hash). The `value` column is a TEXT type by default but if you
105
- want to optimize your DB size you could change it to a VARCHAR in the migration
106
- if you don't plan on storing large values.
107
-
108
-
109
- What if I want to change the table name?
110
- --
111
- By default, `eav_hash` uses a table name derived from the following:
112
-
113
- ```ruby
114
- "<ClassName>_<hash_name>".tableize
115
- ```
116
-
117
- You can change this by passing a symbol to the `:table_name` argument:
118
-
119
- ```ruby
120
- class Widget < ActiveRecord::Base
121
- eav_hash_for :foobar, table_name: :bar_foo
122
- end
123
- ```
124
-
125
- Just remember to edit the table name in the migration, or use the following
126
- migration generator:
127
-
128
- $ rails generate eav_migration Widget foobar bar_foo
129
-
130
-
131
- What's the catch?
132
- -
133
- By using this software, you agree to write me into your will as your next of
134
- kin, and to sacrifice the soul of your first born child to Beelzebub.
135
-
136
- Just kidding, the code is released under the MIT license so you can use it for
137
- whatever purposes you see fit. Just don't sue me if your application blows up
138
- from the sheer awesomeness! Check out the LICENSE file for more information.
139
-
140
- Special Thanks!
141
- -
142
- Thanks to [Matt Kimmel](https://github.com/mattkimmel) for adding support for models contained in namespaces.
143
-
144
- I found a bug or want to contribute!
145
- -
146
- You're probably reading this from GitHub, so you know what to do. If not, the
147
- Github project is at https://github.com/200proof/eav_hashes
1
+ eav_hashes
2
+ =========
3
+
4
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/iostat/eav_hashes) [![Build Status](https://travis-ci.org/iostat/eav_hashes.png?branch=master)](https://travis-ci.org/iostat/eav_hashes)
5
+
6
+ `eav_hashes` is a neato gem for implementing the EAV (entity-attribute-value)
7
+ database design pattern in your Rails models. All you need to do is add one
8
+ line to your model's code and that's it! Schema generation is automatically
9
+ handled for you.
10
+
11
+ Why would I need it?
12
+ -
13
+ Rails' ActiveRecord includes a helper function, `serialize`, to allow you to
14
+ save complex data types (like hashes) into your database. Unfortunately, it
15
+ isn't very useful. A lot of overhead is created from serialization and
16
+ deserialization, and you can't search by the contents of your hash. That's
17
+ where `eav_hashes` comes in.
18
+
19
+ How does it work?
20
+ -
21
+ Great question! Lets dive in with a simple code example, but first lets set up the gem.
22
+
23
+ Put this in your gemfile...
24
+
25
+ gem "eav_hashes", "~> 1.0.0"
26
+
27
+ ...and update your bundle.
28
+
29
+ $ bundle install
30
+
31
+
32
+ Now, lets make this Rails model.
33
+
34
+ ```ruby
35
+ class Product < ActiveRecord::Base
36
+ eav_hash_for :tech_specs
37
+ end
38
+ ```
39
+
40
+ Now run this generator to create a migration:
41
+
42
+ $ rails generate eav_migration Product tech_specs
43
+
44
+ And run the migration:
45
+
46
+ $ rake db:migrate
47
+
48
+ Now watch the magic the happen:
49
+
50
+ ```ruby
51
+ # Assuming this whole example is on a blank DB, of course
52
+ a_product = Product.new
53
+ a_product.tech_specs["Widget Power"] = "1.21 GW"
54
+ a_product.tech_specs["Battery Life (hours)"] = 12
55
+ a_product.tech_specs["Warranty (years)"] = 3.5
56
+ a_product.tech_specs["RoHS Compliant"] = true
57
+ a_product.save!
58
+
59
+ # Setting a value to nil deletes the entry
60
+ a_product.tech_specs["Warranty (years)"] = nil
61
+ a_product.save!
62
+
63
+ the_same_product = Product.first
64
+ puts the_same_product.tech_specs["nonexistant key"]
65
+
66
+ # magic alert: this actually gets the count of EVERY entry of every
67
+ # hash for this model, but for this example this works
68
+ puts "Entry Count: #{ProductTechSpecsEntry.count}"
69
+ the_same_product.tech_specs.each_pair do |key, value|
70
+ puts "#{key}: #{value.to_s}"
71
+ end
72
+
73
+ # Ruby's default types: Integer, Float, Complex, Rational, Symbol,
74
+ # TrueClass, and FalseClass are preserved between transactions like
75
+ # you would expect them to.
76
+ puts the_same_product.tech_specs["Battery Life (hours)"]+3
77
+ ```
78
+
79
+ And the output, as you can expect, will be along the lines of:
80
+
81
+ nil
82
+ Entry Count: 3
83
+ Widget Power: 1.21 GW
84
+ Battery Life (hours): 12
85
+ RoHS Compliant: true
86
+ 15
87
+
88
+
89
+ That looks incredibly simple, right? Good! It's supposed to be! All the magic
90
+ happens when you call `save!`.
91
+
92
+ Now you could start doing other cool stuff, like searching for products based
93
+ on their tech specs! You've already figured out how to do this, haven't you?
94
+
95
+ ```ruby
96
+ flux_capacitor = Product.find_by_tech_specs("Widget Power", "1.21 GW")
97
+ ```
98
+
99
+ Nifty, right?
100
+
101
+ Can I store arrays/hashes/custom types inside my hashes?
102
+ --
103
+ Sure, but they'll be serialized into YAML (so you cant search by them like you
104
+ would an eav_hash). The `value` column is a TEXT type by default but if you
105
+ want to optimize your DB size you could change it to a VARCHAR in the migration
106
+ if you don't plan on storing large values.
107
+
108
+
109
+ What if I want to change the table name?
110
+ --
111
+ By default, `eav_hash` uses a table name derived from the following:
112
+
113
+ ```ruby
114
+ "<ClassName>_<hash_name>".tableize
115
+ ```
116
+
117
+ You can change this by passing a symbol to the `:table_name` argument:
118
+
119
+ ```ruby
120
+ class Widget < ActiveRecord::Base
121
+ eav_hash_for :foobar, table_name: :bar_foo
122
+ end
123
+ ```
124
+
125
+ Just remember to edit the table name in the migration, or use the following
126
+ migration generator:
127
+
128
+ $ rails generate eav_migration Widget foobar bar_foo
129
+
130
+
131
+ What's the catch?
132
+ -
133
+ By using this software, you agree to write me into your will as your next of
134
+ kin, and to sacrifice the soul of your first born child to Beelzebub.
135
+
136
+ Just kidding, the code is released under the MIT license so you can use it for
137
+ whatever purposes you see fit. Just don't sue me if your application blows up
138
+ from the sheer awesomeness! Check out the LICENSE file for more information.
139
+
140
+ Special Thanks!
141
+ -
142
+ Thanks to [Matt Kimmel](https://github.com/mattkimmel) for adding support for models contained in namespaces.
143
+
144
+ I found a bug or want to contribute!
145
+ -
146
+ You're probably reading this from GitHub, so you know what to do. If not, the
147
+ Github project is at https://github.com/iostat/eav_hashes
data/Rakefile CHANGED
@@ -1,30 +1,30 @@
1
- #!/usr/bin/env rake
2
- begin
3
- require 'bundler/setup'
4
- rescue LoadError
5
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
- end
7
-
8
- begin
9
- require 'rdoc/task'
10
- rescue LoadError
11
- require 'rdoc/rdoc'
12
- require 'rake/rdoctask'
13
- RDoc::Task = Rake::RDocTask
14
- end
15
-
16
- RDoc::Task.new(:rdoc) do |rdoc|
17
- rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'EavHashes'
19
- rdoc.options << '--line-numbers'
20
- rdoc.rdoc_files.include('lib/**/*.rb')
21
- end
22
-
23
- Bundler::GemHelper.install_tasks
24
-
25
- require "rspec/core"
26
- require "rspec/core/rake_task"
27
-
28
- RSpec::Core::RakeTask.new(:spec)
29
-
30
- task :default => :spec
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ begin
9
+ require 'rdoc/task'
10
+ rescue LoadError
11
+ require 'rdoc/rdoc'
12
+ require 'rake/rdoctask'
13
+ RDoc::Task = Rake::RDocTask
14
+ end
15
+
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'EavHashes'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ require "rspec/core"
26
+ require "rspec/core/rake_task"
27
+
28
+ RSpec::Core::RakeTask.new(:spec)
29
+
30
+ task :default => :spec
@@ -1,37 +1,37 @@
1
- module ActiveRecord
2
- module EavHashes
3
- def self.included (base)
4
- base.extend ActiveRecord::EavHashes::ClassMethods
5
- end
6
-
7
- module ClassMethods
8
- def eav_hash_for (hash_name, options={})
9
- # Fill in default options not otherwise specified
10
- options[:hash_name] = hash_name
11
- options[:parent_class_name] = self.name.to_sym
12
- options = ActiveRecord::EavHashes::Util::fill_options_hash options
13
-
14
- # Store the options hash in a class variable to create the EavHash object
15
- # if and when it's actually used.
16
- class_variable_set "@@#{hash_name}_hash_options".to_sym, options
17
-
18
- # Create the association, the entry update hook, and a helper method to lazy-load the entries
19
- class_eval <<-END_EVAL
20
- has_many :#{options[:entry_assoc_name]}, class_name: #{options[:entry_class_name]}, foreign_key: "#{options[:parent_assoc_name]}_id", dependent: :delete_all
21
- after_save :save_#{hash_name}
22
- def #{hash_name}
23
- @#{hash_name} ||= ActiveRecord::EavHashes::EavHash.new(self, @@#{hash_name}_hash_options)
24
- end
25
-
26
- def save_#{hash_name}
27
- @#{hash_name}.save_entries if @#{hash_name}
28
- end
29
-
30
- def self.find_by_#{hash_name} (key, value=nil)
31
- self.find (ActiveRecord::EavHashes::Util::run_find_expression(key, value, @@#{hash_name}_hash_options))
32
- end
33
- END_EVAL
34
- end
35
- end
36
- end
37
- end
1
+ module ActiveRecord
2
+ module EavHashes
3
+ def self.included (base)
4
+ base.extend ActiveRecord::EavHashes::ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def eav_hash_for (hash_name, options={})
9
+ # Fill in default options not otherwise specified
10
+ options[:hash_name] = hash_name
11
+ options[:parent_class_name] = self.name.to_sym
12
+ options = ActiveRecord::EavHashes::Util::fill_options_hash options
13
+
14
+ # Store the options hash in a class variable to create the EavHash object
15
+ # if and when it's actually used.
16
+ class_variable_set "@@#{hash_name}_hash_options".to_sym, options
17
+
18
+ # Create the association, the entry update hook, and a helper method to lazy-load the entries
19
+ class_eval <<-END_EVAL
20
+ has_many :#{options[:entry_assoc_name]}, class_name: #{options[:entry_class_name]}, foreign_key: "#{options[:parent_assoc_name]}_id", dependent: :delete_all
21
+ after_save :save_#{hash_name}
22
+ def #{hash_name}
23
+ @#{hash_name} ||= ActiveRecord::EavHashes::EavHash.new(self, @@#{hash_name}_hash_options)
24
+ end
25
+
26
+ def save_#{hash_name}
27
+ @#{hash_name}.save_entries if @#{hash_name}
28
+ end
29
+
30
+ def self.find_by_#{hash_name} (key, value=nil)
31
+ self.find (ActiveRecord::EavHashes::Util::run_find_expression(key, value, @@#{hash_name}_hash_options))
32
+ end
33
+ END_EVAL
34
+ end
35
+ end
36
+ end
37
+ end