hash_accessor 1.0.2 → 1.0.4
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.
- data/README.rdoc +12 -12
- data/hash_accessor.gemspec +6 -6
- data/lib/hash_accessor.rb +5 -5
- data/lib/hash_accessor/class_methods.rb +72 -60
- data/lib/hash_accessor/railtie.rb +3 -3
- data/test/hash_accessor_test.rb +17 -12
- metadata +12 -6
data/README.rdoc
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
= HashAccessor
|
2
2
|
|
3
|
-
This gem provides
|
3
|
+
This gem provides similar functionality to Rails' new ActiveAttr, except with a bunch of powerful methods behind it. Type definitions, defaults, lambdas on arrays, and more.
|
4
4
|
|
5
|
-
The purpose behind building HashAccessor was to be able to quickly add/modify/remove variables being stored in a serialized hash of a rails model. This is very useful if you have a large list of often changing variables on a model which don't get queried against. You can create new variables without messing up your DB. Storing account configurations or custom themes is a common scenario.
|
5
|
+
The purpose behind building HashAccessor was to be able to quickly add/modify/remove variables being stored in a serialized hash of a rails model. This is very useful if you have a large list of often changing variables on a model which don't get queried against. You can create new variables without messing up your DB. Storing account configurations or custom themes is a common scenario.
|
6
6
|
|
7
7
|
This gem was designed to have HTML forms update directly to the hash, but maintain the correct class (respecting :attr_accessible of course). Options like :default, :type, and :collects are particularly helpful when dealing with forms.
|
8
8
|
|
9
|
-
== Installation
|
9
|
+
== Installation
|
10
10
|
|
11
11
|
In your <code>Gemfile</code>:
|
12
12
|
|
13
13
|
gem "hash_accessor"
|
14
14
|
|
15
15
|
Then run:
|
16
|
-
|
16
|
+
|
17
17
|
bundle install
|
18
|
-
|
18
|
+
|
19
19
|
== Usage
|
20
20
|
|
21
21
|
You define each accessor you want to be stored inside the serialized hash
|
@@ -30,24 +30,24 @@ Here is an example:
|
|
30
30
|
hash_accessor :options, :currency, :default => "$USD"
|
31
31
|
hash_accessor :options, :display_currency_on_invoices, :type => :boolean, :default => true
|
32
32
|
hash_accessor :options, :invoice_due_date_net, :type => :integer, :default => 3
|
33
|
-
|
34
|
-
|
33
|
+
|
34
|
+
|
35
35
|
def some_method
|
36
|
-
|
36
|
+
|
37
37
|
self.currency = "$CAD"
|
38
|
-
|
38
|
+
|
39
39
|
display_currency_on_invoices?
|
40
|
-
|
40
|
+
|
41
41
|
...
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
end
|
45
45
|
|
46
46
|
=== Valid Options:
|
47
47
|
|
48
48
|
<code>:default</code> - if undefined, this plugin will create an empty instance of the defined type or null
|
49
49
|
|
50
|
-
<code>:type</code> - defaults to :string. Can also be :integer, :float, :boolean, or :array
|
50
|
+
<code>:type</code> - defaults to :string. Can also be :integer, :float, :decimal, :boolean, or :array
|
51
51
|
|
52
52
|
==== For Arrays only:
|
53
53
|
<code>:collects</code> - only runs on arrays. Calls the lambda method on each item in the array before saving
|
data/hash_accessor.gemspec
CHANGED
@@ -6,20 +6,20 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.author = ["Forrest"]
|
7
7
|
s.email = ["development@forrestzeisler.com"]
|
8
8
|
s.date = Time.now.utc.strftime("%Y-%m-%d")
|
9
|
-
|
10
|
-
|
9
|
+
|
10
|
+
|
11
11
|
s.description = 'This gem provides accessor methods to hash keys.'
|
12
12
|
s.summary = "This gem provides extended functionality to serialized hashed in rails. It allows you to define accessor methods for variable that rest "+
|
13
13
|
"inside a serialized hash. This is very useful if you have a large list of often changing DB variables on a model which don't get queried against."
|
14
|
-
|
14
|
+
|
15
15
|
s.required_rubygems_version = ">= 1.3.6"
|
16
16
|
s.platform = Gem::Platform::RUBY
|
17
|
-
s.add_dependency 'activesupport', '>= 3.
|
17
|
+
s.add_dependency 'activesupport', '>= 3.2.0'
|
18
18
|
|
19
19
|
s.files = `git ls-files`.split("\n")
|
20
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
21
|
s.require_path = "lib"
|
22
|
-
|
22
|
+
|
23
23
|
s.has_rdoc = true
|
24
24
|
s.extra_rdoc_files = ["README.rdoc"]
|
25
|
-
end
|
25
|
+
end
|
data/lib/hash_accessor.rb
CHANGED
@@ -4,12 +4,12 @@ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname
|
|
4
4
|
require 'hash_accessor/railtie' if defined?(Rails)
|
5
5
|
|
6
6
|
module HashAccessor
|
7
|
-
VERSION = "1.0.
|
8
|
-
|
9
|
-
autoload :ClassMethods, 'hash_accessor/class_methods'
|
10
|
-
|
7
|
+
VERSION = "1.0.4"
|
8
|
+
|
9
|
+
autoload :ClassMethods, 'hash_accessor/class_methods'
|
10
|
+
|
11
11
|
def self.included(mod)
|
12
12
|
mod.extend(ClassMethods)
|
13
13
|
end
|
14
14
|
|
15
|
-
end
|
15
|
+
end
|
@@ -1,7 +1,12 @@
|
|
1
1
|
require 'active_support/core_ext/object/blank'
|
2
|
+
require 'active_support/core_ext/object/try'
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
require "bigdecimal"
|
5
|
+
require "bigdecimal/util"
|
2
6
|
|
3
7
|
module HashAccessor
|
4
8
|
module ClassMethods
|
9
|
+
|
5
10
|
#valid options:
|
6
11
|
# :default - if undefined, this plugin will create an empty instance of the defined type or null
|
7
12
|
# :type - defaults to :string. Can also be :integer, :float, :boolean, or :array
|
@@ -10,81 +15,88 @@ module HashAccessor
|
|
10
15
|
# :collects - only runs on arrays. Calls the lambda method on each item in the array before saving
|
11
16
|
# :reject_blanks - removes all blank elements after the collect method
|
12
17
|
def hash_accessor(hash_name, method_name, options = {})
|
13
|
-
method_modifier = ""
|
14
18
|
begin
|
15
|
-
|
16
|
-
|
17
|
-
method_modifier = "new_val = new_val.to_i"
|
18
|
-
elsif options[:type]==:float
|
19
|
-
method_modifier = "new_val = new_val.to_f"
|
20
|
-
elsif options[:type]==:boolean or options[:type]==:bool
|
21
|
-
method_modifier = "new_val = (new_val.is_a?(TrueClass) or (new_val.is_a?(String) and (new_val=~/true|1/i).present?) or (new_val.is_a?(Fixnum) and new_val==1))"
|
22
|
-
elsif options[:type]==:array
|
23
|
-
method_modifier = "new_val = [new_val] unless new_val.is_a?(Array)"
|
19
|
+
method_modifier = hash_accessor_method_modifier(method_name, options)
|
20
|
+
default = hash_accessor_default(options)
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if options[:reject_blanks]
|
31
|
-
method_modifier += "\nnew_val = new_val.reject(&:blank?)"
|
22
|
+
# Define getter
|
23
|
+
define_method(method_name) do
|
24
|
+
send("#{hash_name}=", {}) if send(hash_name).blank?
|
25
|
+
if self.send(hash_name)[method_name].nil?
|
26
|
+
self.send(hash_name)[method_name] = default
|
32
27
|
end
|
28
|
+
self.send(hash_name)[method_name]
|
33
29
|
end
|
34
30
|
|
31
|
+
# Define setter
|
32
|
+
define_method("#{method_name}=") do |*args|
|
33
|
+
new_val = args[0]
|
34
|
+
self.send("#{hash_name}=", {}) if send(hash_name).blank?
|
35
|
+
new_val = method_modifier.call(new_val)
|
36
|
+
if self.send(hash_name)[method_name] != new_val
|
37
|
+
instance_variable_set("@#{method_name}_changed", true)
|
38
|
+
end
|
39
|
+
self.send(hash_name)[method_name] = new_val
|
40
|
+
end
|
35
41
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
elsif options[:default].nil? and options[:type]==:array
|
40
|
-
default = "[]"
|
41
|
-
elsif options[:default].nil?
|
42
|
-
default = "nil"
|
43
|
-
else
|
44
|
-
default = options[:default]
|
42
|
+
# Define changed?
|
43
|
+
define_method("#{method_name}_changed?") do
|
44
|
+
!!instance_variable_get("@#{method_name}_changed")
|
45
45
|
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
# Define special boolean accessor
|
48
|
+
if options[:type]==:boolean or options[:type]==:bool
|
49
|
+
define_method("#{method_name}?") do
|
50
|
+
!!send(method_name)
|
51
|
+
end
|
52
|
+
end
|
50
53
|
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
+
rescue Exception => e
|
55
|
+
puts "\n\nError adding hash_accessor:\n#{e.message}\n#{e.backtrace}\n\n"
|
56
|
+
end
|
57
|
+
end
|
54
58
|
|
55
|
-
|
56
|
-
end
|
59
|
+
private
|
57
60
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
+
def hash_accessor_method_modifier(method_name, options)
|
62
|
+
case options[:type]
|
63
|
+
when :integer
|
64
|
+
lambda {|new_val| new_val.try(:to_i) }
|
65
|
+
when :float
|
66
|
+
lambda {|new_val| new_val.try(:to_f) }
|
67
|
+
when :decimal
|
68
|
+
lambda {|new_val| new_val.try(:to_d) }
|
69
|
+
when :boolean, :bool
|
70
|
+
lambda {|new_val| (new_val.is_a?(TrueClass) or (new_val.is_a?(String) and (new_val=~/true|1/i).present?) or (new_val.is_a?(Fixnum) and new_val==1)) }
|
71
|
+
when :array
|
72
|
+
lambda {|new_val|
|
73
|
+
new_val = Array.wrap(new_val)
|
61
74
|
|
62
|
-
if
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
self.#{hash_name}[:#{method_name}] = new_val
|
67
|
-
end
|
75
|
+
if options[:collects]
|
76
|
+
new_val = new_val.collect(&options[:collects])
|
77
|
+
end
|
68
78
|
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
EOS
|
79
|
+
if options[:reject_blanks]
|
80
|
+
new_val.reject!(&:blank?)
|
81
|
+
end
|
73
82
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
EOS
|
80
|
-
end
|
83
|
+
new_val
|
84
|
+
}
|
85
|
+
else lambda {|new_val| new_val}
|
86
|
+
end
|
87
|
+
end
|
81
88
|
|
82
|
-
|
83
|
-
|
84
|
-
|
89
|
+
def hash_accessor_default(options)
|
90
|
+
if options[:default].is_a?(String)
|
91
|
+
default = options[:default]
|
92
|
+
elsif options[:default].nil? and options[:type]==:array
|
93
|
+
default = []
|
94
|
+
elsif options[:default].nil?
|
95
|
+
default = nil
|
96
|
+
else
|
97
|
+
default = options[:default]
|
85
98
|
end
|
86
|
-
|
87
99
|
end
|
88
100
|
end
|
89
|
-
|
90
|
-
end
|
101
|
+
|
102
|
+
end
|
data/test/hash_accessor_test.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'test/unit'
|
2
|
+
|
2
3
|
require File.expand_path("../lib/hash_accessor", File.dirname(__FILE__))
|
3
4
|
|
4
5
|
class HashAccessorTest < Test::Unit::TestCase
|
@@ -6,50 +7,54 @@ class HashAccessorTest < Test::Unit::TestCase
|
|
6
7
|
class TestClassWithHash
|
7
8
|
include HashAccessor
|
8
9
|
attr_accessor :options
|
9
|
-
|
10
|
+
|
10
11
|
hash_accessor :options, :unspecified_variable
|
11
12
|
hash_accessor :options, :test_integer, :type => :integer
|
13
|
+
hash_accessor :options, :test_decimal, :type => :decimal
|
12
14
|
hash_accessor :options, :test_bool, :type => :bool
|
13
|
-
hash_accessor :options, :test_array_1, :type => :array, :collects => lambda{|item|
|
15
|
+
hash_accessor :options, :test_array_1, :type => :array, :collects => lambda{|item|
|
16
|
+
item.gsub(/li_/, "").to_i
|
17
|
+
}
|
14
18
|
hash_accessor :options, :test_array_2, :type => :array, :reject_blanks => true
|
15
|
-
|
19
|
+
|
16
20
|
def initialize
|
17
21
|
options = {}
|
18
22
|
end
|
19
23
|
end
|
20
|
-
|
24
|
+
|
21
25
|
def setup
|
22
26
|
@tester = TestClassWithHash.new
|
23
27
|
end
|
24
28
|
|
25
29
|
def test_accessors_being_added_correct
|
26
30
|
assert @tester.respond_to?(:unspecified_variable)
|
27
|
-
|
31
|
+
|
28
32
|
@tester.unspecified_variable = "some test"
|
29
33
|
assert_equal "some test", @tester.unspecified_variable
|
30
34
|
end
|
31
|
-
|
35
|
+
|
32
36
|
def test_accessors_being_casted_correctly
|
33
37
|
@tester.test_integer = "3"
|
38
|
+
@tester.test_decimal = "3"
|
34
39
|
assert_equal 3, @tester.test_integer
|
40
|
+
assert_equal 3.to_d, @tester.test_decimal
|
35
41
|
end
|
36
|
-
|
42
|
+
|
37
43
|
def test_boolean_question_mark_method_being_added
|
38
44
|
assert !@tester.test_bool?
|
39
45
|
@tester.test_bool = true
|
40
46
|
assert @tester.test_bool?
|
41
47
|
end
|
42
|
-
|
48
|
+
|
43
49
|
def test_array_collect_method
|
44
50
|
assert_equal [], @tester.test_array_1
|
45
51
|
@tester.test_array_1 = ["li_1", "li_2", "li_3"]
|
46
52
|
assert_equal [1, 2, 3], @tester.test_array_1
|
47
53
|
end
|
48
|
-
|
54
|
+
|
49
55
|
def test_array_reject_blank_method
|
50
56
|
@tester.test_array_2 = ["", "1", "2"]
|
51
57
|
assert_equal ["1", "2"], @tester.test_array_2
|
52
58
|
end
|
53
|
-
|
54
|
-
|
55
|
-
end
|
59
|
+
|
60
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_accessor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,19 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 3.
|
21
|
+
version: 3.2.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.0
|
25
30
|
description: This gem provides accessor methods to hash keys.
|
26
31
|
email:
|
27
32
|
- development@forrestzeisler.com
|
@@ -60,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
65
|
version: 1.3.6
|
61
66
|
requirements: []
|
62
67
|
rubyforge_project:
|
63
|
-
rubygems_version: 1.8.
|
68
|
+
rubygems_version: 1.8.22
|
64
69
|
signing_key:
|
65
70
|
specification_version: 3
|
66
71
|
summary: This gem provides extended functionality to serialized hashed in rails. It
|
@@ -69,3 +74,4 @@ summary: This gem provides extended functionality to serialized hashed in rails.
|
|
69
74
|
on a model which don't get queried against.
|
70
75
|
test_files:
|
71
76
|
- test/hash_accessor_test.rb
|
77
|
+
has_rdoc: true
|