eav_hashes 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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