magic_meta_methods 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Nick Zalabak
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 ADDED
@@ -0,0 +1,64 @@
1
+ = magic_meta_methods
2
+
3
+ == Instructions
4
+
5
+ A plugin to generate many methods or "attributes" on ActiveRecord that
6
+ persists data into a serialized text based column as defined by :column. This
7
+ plugin is particularly useful for storing display data or meta data that isn't intended to be queried
8
+ directly via SQL. It reduces the number of "one-off" columns and the clutter of serialized declarations
9
+ with getter/setters on your model.
10
+
11
+ == Installation
12
+
13
+ ruby script/plugin install git://github.com/techwhizbang/magic_meta_methods.git
14
+
15
+ == Usage
16
+
17
+ === Prepare database
18
+
19
+ Add this migration to the desired table(s):
20
+
21
+ class MagicMetaMethods < ActiveRecord::Migration
22
+ def self.up
23
+ add_column :your_table_here, :magic_meta_methods, :mediumtext
24
+ end
25
+
26
+ def self.down
27
+ remove_column :your_table_here, :magic_meta_methods
28
+ end
29
+ end
30
+
31
+ rake db:migrate
32
+
33
+ === Meta Magic Methods in action
34
+
35
+ Let's suppose your model needs to store a variety of data and types, but
36
+ these values don't need to be queried on, many times these values are purely
37
+ for display or front end purposes.
38
+
39
+ class YourModel < ActiveRecord::Base
40
+ magic_meta_methods([:abstract,
41
+ [:some_hash, :hash],
42
+ [:some_array, :array],
43
+ [:some_indifferent_hash, :indifferent_hash]], :column => 'alternate_meta')
44
+ end
45
+
46
+ We can now use the magic meta methods just like a regular attribute setter
47
+
48
+ m = YourModel.new
49
+ m.abstract= "This is a brief synopsis of magic meta methods"
50
+ m.some_hash = {:a => 1, :b => 2, :c => 3}
51
+ m.some_array = [["Monday", "9-5"], ["Tuesday", "9-5"], ["Wed", "Closed"]]
52
+ m.some_indifferent_hash = {:dog => "Fido", :cat => "Garfield"}
53
+ m.save
54
+
55
+ You can retrieve the values
56
+
57
+ m.some_indifferent_hash['dog'] #Fido
58
+ m.abstract #This is a brief synopsis of magic meta methods
59
+ m.some_array[0] #["Monday", "9-5"]
60
+
61
+ === Other
62
+
63
+ Problems, comments, and suggestions all welcome. techwhizbang [at] gmail dot com or visit my blog
64
+ http://techwhizbang.com
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |s|
7
+ s.name = "magic_meta_methods"
8
+ s.summary = "A gem that polishes ActiveRecord data serialization to make it really awesome"
9
+ s.description = "magic_meta_methods uses ActiveRecord data serialization and allows for several objects by key to be stored in _one_ column while still providing the same attr_accessor behavior as if there were a column for _each_ serialized object - hence the magic 'meta' methods"
10
+ s.email = "techwhizbang@gmail.com"
11
+ s.homepage = "http://github.com/techwhizbang/magic_meta_methods"
12
+ s.rubyforge_project = 'magic_meta_methods'
13
+ s.authors = ["Nick Zalabak"]
14
+ s.files = FileList["[A-Za-z]*", "{lib,test}/**/*"]
15
+ s.test_files = FileList["test/**/*"]
16
+ s.add_dependency "activerecord", ">= 2.3.2"
17
+ end
18
+
19
+ rescue LoadError
20
+ puts "Jeweler not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ Rake::TestTask.new do |t|
24
+ t.libs << 'lib'
25
+ t.pattern = 'test/**/*_test.rb'
26
+ t.verbose = false
27
+ end
28
+
29
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'activerecord'
2
+ require 'magic_meta_methods'
@@ -0,0 +1,85 @@
1
+ module ActiveRecord
2
+
3
+ module MagicMetaMethods
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ class << base
8
+ attr_accessor :meta_methods_column
9
+ attr_accessor :meta_methods_declarations
10
+ end
11
+ base.send(:before_create, :init_meta_methods)
12
+ end
13
+
14
+ module ClassMethods
15
+ def magic_meta_methods(methods=[], options={})
16
+
17
+ column_name = options[:column].blank? ? :magic_meta_methods : options[:column].to_sym
18
+ self.meta_methods_column = column_name
19
+ self.meta_methods_declarations = methods
20
+ self.meta_methods_declarations.each do |attribute|
21
+ if attribute.is_a?(Array)
22
+ name = attribute[0]
23
+ type = attribute[1]
24
+ else
25
+ #default to string since its the most common usage
26
+ name = attribute
27
+ type = :string
28
+ end
29
+
30
+ serialize column_name
31
+ define_method(name.to_sym) { self.get_meta_value(name, type)}
32
+ define_method((name.to_s + '=').to_sym) {|val| self.set_meta_value(name, val, type)}
33
+ end
34
+ end
35
+ end
36
+
37
+ def init_meta_methods
38
+ self[self.class.meta_methods_column] = {} unless self[self.class.meta_methods_column].kind_of?(Hash)
39
+ end
40
+
41
+ def set_meta_value(method_name, val, type)
42
+ init_meta_methods #should never happen, but a failsafe
43
+ self[self.class.meta_methods_column][method_name] = convert_to_type(val, type)
44
+ end
45
+
46
+ def get_meta_value(method_name, type)
47
+ return nil unless self[self.class.meta_methods_column].kind_of?(Hash)
48
+ convert_to_type(self[self.class.meta_methods_column][method_name], type)
49
+ end
50
+
51
+ def convert_to_type (val, type)
52
+ return nil if val.nil? or (val.is_a?(String) and val.blank?)
53
+ converted_value = nil
54
+ case type
55
+ when :string
56
+ converted_value = val.to_s
57
+ when :integer
58
+ converted_value = val.to_i
59
+ when :float
60
+ converted_value = val.to_f
61
+ when :date
62
+ converted_value = val.is_a?(Date) ? val : Date.parse(val.to_s, true)
63
+ when :time
64
+ converted_value = val.is_a?(Time) ? val : Time.parse(val.to_s, true)
65
+ when :datetime
66
+ converted_value = val.is_a?(DateTime) ? val : DateTime.parse(val.to_s)
67
+ when :indifferent_hash
68
+ converted_value = val.is_a?(HashWithIndifferentAccess) ? val : (raise InvalidMetaTypeError.new("Invalid HashWithIndifferentAccess #{val}"))
69
+ when :hash
70
+ converted_value = val.is_a?(Hash) ? val : (raise InvalidMetaTypeError.new("Invalid Hash #{val}"))
71
+ when :array
72
+ converted_value = val.is_a?(Array) ? val : [val]
73
+ when val.is_a?(type)
74
+ converted_value = val
75
+ else
76
+ raise InvalidMetaTypeError.new("Invalid type #{type.name}")
77
+ end
78
+ converted_value
79
+ end
80
+ end
81
+ end
82
+
83
+ class InvalidMetaTypeError < ArgumentError; end
84
+
85
+ ActiveRecord::Base.send(:include, ActiveRecord::MagicMetaMethods)
@@ -0,0 +1,51 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{magic_meta_methods}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nick Zalabak"]
12
+ s.date = %q{2010-03-09}
13
+ s.description = %q{magic_meta_methods uses ActiveRecord data serialization and allows for several objects by key to be stored in _one_ column while still providing the same attr_accessor behavior as if there were a column for _each_ serialized object - hence the magic 'meta' methods}
14
+ s.email = %q{techwhizbang@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ "MIT-LICENSE",
20
+ "README",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "init.rb",
24
+ "lib/magic_meta_methods.rb",
25
+ "magic_meta_methods.gemspec",
26
+ "test/magic_meta_methods_test.rb"
27
+ ]
28
+ s.homepage = %q{http://github.com/techwhizbang/magic_meta_methods}
29
+ s.rdoc_options = ["--charset=UTF-8"]
30
+ s.require_paths = ["lib"]
31
+ s.rubyforge_project = %q{magic_meta_methods}
32
+ s.rubygems_version = %q{1.3.5}
33
+ s.summary = %q{A gem that polishes ActiveRecord data serialization to make it really awesome}
34
+ s.test_files = [
35
+ "test/magic_meta_methods_test.rb"
36
+ ]
37
+
38
+ if s.respond_to? :specification_version then
39
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
+ s.specification_version = 3
41
+
42
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.3.2"])
44
+ else
45
+ s.add_dependency(%q<activerecord>, [">= 2.3.2"])
46
+ end
47
+ else
48
+ s.add_dependency(%q<activerecord>, [">= 2.3.2"])
49
+ end
50
+ end
51
+
@@ -0,0 +1,174 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ gem 'activerecord'
5
+ require 'active_record'
6
+
7
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/magic_meta_methods")
8
+
9
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
10
+
11
+ def setup_db
12
+ ActiveRecord::Schema.define(:version => 1) do
13
+ create_table :base_meta_models do |t|
14
+ t.column :magic_meta_methods, :text
15
+ t.column :type, :string
16
+ t.column :alternate_meta, :text
17
+ end
18
+ end
19
+ end
20
+
21
+ def teardown_db
22
+ ActiveRecord::Base.connection.tables.each do |table|
23
+ ActiveRecord::Base.connection.drop_table(table)
24
+ end
25
+ end
26
+
27
+ class BaseMetaModel < ActiveRecord::Base
28
+ magic_meta_methods([
29
+ :a_string,
30
+ [:a_hash, :hash],
31
+ [:hours, :array],
32
+ [:cats, :indifferent_hash]]
33
+ )
34
+ end
35
+
36
+ class MetaModel < BaseMetaModel
37
+ magic_meta_methods([
38
+ :a_string,
39
+ [:a_hash, :hash],
40
+ [:hours, :array],
41
+ [:cats, :indifferent_hash]]
42
+ )
43
+ end
44
+
45
+ class MetaModelChild < MetaModel
46
+ magic_meta_methods(
47
+ [:a_string]
48
+ )
49
+ end
50
+
51
+ class EmptyMetaModel < MetaModel
52
+ magic_meta_methods
53
+ end
54
+
55
+ class AlternateColumnMetaModel < BaseMetaModel
56
+ magic_meta_methods([:a_string,
57
+ [:a_hash, :hash],
58
+ [:hours, :array],
59
+ [:cats, :indifferent_hash]], :column => 'alternate_meta')
60
+ end
61
+
62
+ class MagicMetaMethodsTest < Test::Unit::TestCase
63
+
64
+ def setup
65
+ setup_db
66
+ (1..4).each do |counter|
67
+ m = MetaModel.create!
68
+ m.a_string = "yes"
69
+ m.a_hash = {:a => 1}
70
+ m.hours = ["1", "2", "3"]
71
+ m.cats = HashWithIndifferentAccess.new(:cat => "cat", :cat2 => "cat2", "cat3" => "cat3")
72
+ m.save!
73
+ end
74
+ MetaModelChild.create!
75
+ end
76
+
77
+ def teardown
78
+ teardown_db
79
+ end
80
+
81
+ def test_alternate_column_name
82
+ assert_equal AlternateColumnMetaModel.meta_methods_column, :alternate_meta
83
+ end
84
+
85
+ def test_meta_method_persistance
86
+ assert_equal "yes", MetaModel.first.a_string
87
+ end
88
+
89
+ def test_alternate_column_create_with_meta_data
90
+ a = AlternateColumnMetaModel.create!(:a_string => 'hello', :a_hash => {:a => 1, :b => 2})
91
+ a = AlternateColumnMetaModel.first
92
+ assert_equal('hello', a.a_string)
93
+ assert_equal({:a => 1, :b => 2}, a.a_hash)
94
+ assert_not_nil(a.alternate_meta)
95
+ end
96
+
97
+ def test_meta_method_hashes
98
+ assert_equal({:a => 1}, MetaModel.first.a_hash)
99
+ end
100
+
101
+ def test_meta_method_indifferent_hashes
102
+ assert_equal({"cat"=>"cat", "cat2"=>"cat2", "cat3"=>"cat3"}, MetaModel.first.cats)
103
+ end
104
+
105
+
106
+ def test_update_meta_method_value
107
+ m = MetaModel.first
108
+ m.a_string = "changed"
109
+ m.save!
110
+ assert_equal "changed", MetaModel.first.a_string
111
+ end
112
+
113
+ def test_empty_meta_method_should_return_nil
114
+ assert_equal nil, MetaModelChild.first.a_string
115
+ end
116
+
117
+ def test_blank_declaration_of_meta_methods_class
118
+ assert_nothing_raised do
119
+ EmptyMetaModel.create!
120
+ end
121
+ end
122
+
123
+ def test_init_meta_methods_should_return_hash_if_nil
124
+ assert_equal({}, MetaModel.new.send(:init_meta_methods))
125
+ end
126
+
127
+ def test_should_convert_string_type
128
+ assert_equal("String", MetaModel.new.send(:convert_to_type, "String", :string))
129
+ end
130
+
131
+ def test_should_convert_hash_type
132
+ assert_equal({:a => 1, :b => 2}, MetaModel.new.send(:convert_to_type, {:a => 1, :b => 2}, :hash))
133
+ end
134
+
135
+ def test_should_convert_date_type
136
+ d = Date.parse("12/5/1982")
137
+ assert_equal(d, MetaModel.new.send(:convert_to_type, d, :date))
138
+ end
139
+
140
+ def test_should_raise_an_error_if_an_invalid_hash
141
+ d = Date.parse("2/5/1998")
142
+ assert_raise(InvalidMetaTypeError) do
143
+ MetaModel.new.send(:convert_to_type, d, :hash)
144
+ end
145
+ end
146
+
147
+ def test_should_convert_time_type
148
+ t = Time.now
149
+ assert_equal(t, MetaModel.new.send(:convert_to_type, t, :time))
150
+ end
151
+
152
+ def test_should_convert_datetime_type
153
+ t = DateTime.now
154
+ assert_equal(t, MetaModel.new.send(:convert_to_type, t, :datetime))
155
+ end
156
+
157
+ def test_should_convert_array_type
158
+ a = [1, 2, "3"]
159
+ assert_equal(a, MetaModel.new.send(:convert_to_type, a, :array))
160
+ end
161
+
162
+ def test_should_convert_integer_type
163
+ assert_equal(1, MetaModel.new.send(:convert_to_type, 1, :integer))
164
+ end
165
+
166
+ def test_should_convert_float_type
167
+ assert_equal(1.123456789, MetaModel.new.send(:convert_to_type, 1.123456789, :float) )
168
+ end
169
+
170
+ def test_should_convert_hash_with_indifferent_access
171
+ hida = HashWithIndifferentAccess.new(:a => 1, :b => 2)
172
+ assert_equal(hida, MetaModel.new.send(:convert_to_type, hida, :indifferent_hash))
173
+ end
174
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: magic_meta_methods
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Zalabak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-09 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.3.2
24
+ version:
25
+ description: magic_meta_methods uses ActiveRecord data serialization and allows for several objects by key to be stored in _one_ column while still providing the same attr_accessor behavior as if there were a column for _each_ serialized object - hence the magic 'meta' methods
26
+ email: techwhizbang@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ files:
34
+ - MIT-LICENSE
35
+ - README
36
+ - Rakefile
37
+ - VERSION
38
+ - init.rb
39
+ - lib/magic_meta_methods.rb
40
+ - magic_meta_methods.gemspec
41
+ - test/magic_meta_methods_test.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/techwhizbang/magic_meta_methods
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project: magic_meta_methods
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A gem that polishes ActiveRecord data serialization to make it really awesome
70
+ test_files:
71
+ - test/magic_meta_methods_test.rb