nested_accessors 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +21 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +142 -0
- data/Rakefile +10 -0
- data/lib/nested_accessors.rb +113 -0
- data/lib/nested_accessors/railtie.rb +9 -0
- data/lib/nested_accessors/version.rb +3 -0
- data/nested_accessors.gemspec +24 -0
- data/spec/nested_accessors_spec.rb +179 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTlmMmU3YzY3YjFlYmU5NzFhMTJiNjIzOTE2Y2RhMzE4YTMxZmJjZg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDlmMDI1Zjg4ZGE0NGM4ZDdjYzQ0ZTI1YjQ5ZDg0M2Y2MjAxMzZmMw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
N2FkOTQ0ZWVlZDViNWY2NmZiMmI4YzRlODEzZWRhMDJmZmQwZWQyYzc3MmYy
|
10
|
+
MDA4NjIzMTlmZDNmMDBlYjVjZTRiNzUyOGRkNjlmMzY4NGQ4NGRjMGNjOTc3
|
11
|
+
ZTk0NmYzNTU1NTlkOTRmZjU4ZDhhMjdlY2FhNjNiMWJkYTA3YTM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjkzODdiMDk5OWRmNDdlNGU5OTg2MDYxZTcyODdlOTNmZDE4NTkxYTBkZTZi
|
14
|
+
NDVhZDJiZjE3OGY0MGYzZWNjMDU0NGUyMmM2NjdmZjQ3MzQ5YzZlYTQ3Y2Fl
|
15
|
+
MDU2NzM4YzA2MTA4ZWZlYWM1OTdhZjNjZDdhZTM2MzBlMzEwNzA=
|
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
.DS_Store
|
2
|
+
*.sublime*
|
3
|
+
.git-old
|
4
|
+
*.gem
|
5
|
+
*.rbc
|
6
|
+
.bundle
|
7
|
+
.config
|
8
|
+
.yardoc
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
21
|
+
Readme.txt
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Oskar L-B
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/avocade/nested_accessors.png?branch=master)](https://travis-ci.org/avocade/nested_accessors) [![Code Climate](https://codeclimate.com/github/avocade/nested_accessors.png)](https://codeclimate.com/github/avocade/nested_accessors)
|
2
|
+
|
3
|
+
NestedAccessors
|
4
|
+
==============
|
5
|
+
|
6
|
+
This class lets you quickly add serialized, nested hash accessors in ActiveRecord
|
7
|
+
model objects, using regular `text` database columns.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Person < ActiveRecord::Base
|
11
|
+
include NestedAccessors
|
12
|
+
|
13
|
+
nested_accessor :info, [ :name, :phone ]
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
This would synthesize accessors to the `name` and `phone` properties contained
|
18
|
+
in the `info` hash.
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
foo = Foo.new
|
22
|
+
foo.name = "bar"
|
23
|
+
foo.phone = "+46-123-45678"
|
24
|
+
foo.info #=> { "name" => "bar", "phone" => "+46-123-45678" }
|
25
|
+
```
|
26
|
+
|
27
|
+
If we want just a single `name` accessor we can remove the array:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
nested_accessor :info, :name
|
31
|
+
```
|
32
|
+
|
33
|
+
|
34
|
+
Installation
|
35
|
+
------------
|
36
|
+
|
37
|
+
- Add the gem to your `Gemfile`:
|
38
|
+
|
39
|
+
source :rubygems
|
40
|
+
gem 'nested_accessors', :git => 'git@github.com:avocade/nested_accessors.git'
|
41
|
+
|
42
|
+
- Run `bundle install`
|
43
|
+
|
44
|
+
|
45
|
+
Dependencies
|
46
|
+
------------
|
47
|
+
|
48
|
+
Requires `ActiveRecord` for the `serialize` class method. _(To be
|
49
|
+
reconsidered.)_
|
50
|
+
|
51
|
+
|
52
|
+
Nested hash
|
53
|
+
------------
|
54
|
+
|
55
|
+
You can nest accessors one level deep. To add more than one
|
56
|
+
nested hash accessor to `address` we specify `street` and `city`
|
57
|
+
inside an array.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
nested_accessor :info, address: [ :street, :city ]
|
61
|
+
```
|
62
|
+
|
63
|
+
This gives:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
object.address_street # these two are nested inside the "address" hash
|
67
|
+
object.address_city
|
68
|
+
```
|
69
|
+
|
70
|
+
To just specify just one accessor, eg `address[street]`, we can simplify:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
nested_accessor :info, address: street
|
74
|
+
```
|
75
|
+
|
76
|
+
**Note**: The hash keys are always strings, never symbols. This is for
|
77
|
+
consistency of input/output.
|
78
|
+
|
79
|
+
|
80
|
+
Testing
|
81
|
+
-------
|
82
|
+
|
83
|
+
Run the `minitest` specs using:
|
84
|
+
|
85
|
+
rake
|
86
|
+
|
87
|
+
|
88
|
+
TODO
|
89
|
+
-----
|
90
|
+
|
91
|
+
- Add assertion checking for args
|
92
|
+
- Switch to using `supermodel` gem for testing `active_model` serialize
|
93
|
+
dependency properly instead of stubbing it out
|
94
|
+
- Allow setting default value for each accessor, eg `last_name: "Doe"`
|
95
|
+
- Create object wrappers for each nested hash, so can get accessors like `person.address.street` for `person[address][street]`
|
96
|
+
- Add two-level nesting, eg `foo[bar][name][surname]`
|
97
|
+
- Array with nested Hash objects inside, eg `foo[bar][1][name]`
|
98
|
+
- Perhaps switch convention to always use symbolic keys instead of
|
99
|
+
stringified keys, so can use new ruby 1.9 hash syntax:
|
100
|
+
|
101
|
+
foo.info = { name: "Anders" }
|
102
|
+
foo.info[:name]
|
103
|
+
|
104
|
+
- Add typed arguments for each accessor (defaults to `String`)
|
105
|
+
|
106
|
+
nested_accessor :info, phone: Integer
|
107
|
+
|
108
|
+
Author
|
109
|
+
------
|
110
|
+
|
111
|
+
Oskar Boethius Lissheim is a Product Designer and iOS & Ruby on Rails developer. He currently lives in Gothenburg, Sweden.
|
112
|
+
|
113
|
+
You can reach him on App.net at
|
114
|
+
[@avocade](http://alpha.app.net/avocade), or
|
115
|
+
[Twitter](http://twitter.com/avocade).
|
116
|
+
|
117
|
+
|
118
|
+
License
|
119
|
+
-------
|
120
|
+
|
121
|
+
This code is offered under the MIT License.
|
122
|
+
|
123
|
+
Copyright © 2012 Oskar Boethius Lissheim.
|
124
|
+
|
125
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
126
|
+
copy of this software and associated documentation files (the
|
127
|
+
"Software"), to deal in the Software without restriction, including
|
128
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
129
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
130
|
+
permit persons to whom the Software is furnished to do so, subject to
|
131
|
+
the following conditions:
|
132
|
+
|
133
|
+
The above copyright notice and this permission notice shall be included
|
134
|
+
in all copies or substantial portions of the Software.
|
135
|
+
|
136
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
137
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
138
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
139
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
140
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
141
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
142
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative "nested_accessors/version"
|
2
|
+
require_relative "nested_accessors/railtie" if defined? Rails
|
3
|
+
|
4
|
+
module NestedAccessors
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
##
|
11
|
+
# Creates new method +nested_accessor+ for adding dynamic accessors to nested hashes, using:
|
12
|
+
# <tt>nested_accessor :pz_settings, confirmation_token: String, subsettings: { foo: String, bar: Integer }</tt>
|
13
|
+
def nested_accessor(name, *args)
|
14
|
+
self.class_eval do
|
15
|
+
serialize name, Hash
|
16
|
+
end
|
17
|
+
|
18
|
+
args.each do |an_arg|
|
19
|
+
if an_arg.is_a? Hash
|
20
|
+
# nested_accessor :info, address: [:foo]
|
21
|
+
an_arg.each do |subroot,propnames|
|
22
|
+
if propnames.is_a? Array # eg "address: [:city, :zipcode]"
|
23
|
+
define_first_level_nesting_methods_for_subroot(name, subroot, Hash, propnames)
|
24
|
+
elsif propnames == Array # eg "address: Array"
|
25
|
+
define_first_level_nesting_methods_for_subroot(name, subroot, Array)
|
26
|
+
elsif propnames.is_a? Symbol # eg "auth: :facebook"
|
27
|
+
define_first_level_nesting_methods_for_subroot(name, subroot, Hash, [propnames])
|
28
|
+
elsif propnames.is_a? Hash # eg "subregion: { address: [:street, :city] }"
|
29
|
+
propnames.each do |subsubroot,subpropnames|
|
30
|
+
define_first_level_nesting_methods_for_subroot(name, subroot, Hash, [subsubroot])
|
31
|
+
define_second_level_nesting_methods(subroot, subsubroot, subpropnames)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
elsif an_arg.is_a? Array
|
36
|
+
an_arg.each do |a_propname|
|
37
|
+
define_first_level_nesting_methods_for_property(name, a_propname)
|
38
|
+
end
|
39
|
+
elsif an_arg.is_a? Symbol
|
40
|
+
define_first_level_nesting_methods_for_property(name, an_arg)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# HELPER METHODS
|
48
|
+
def define_first_level_nesting_methods_for_property(root, propname)
|
49
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
50
|
+
def #{propname}=(val)
|
51
|
+
#{root}.store("#{propname}", val.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def #{propname}
|
55
|
+
#{root}.store("#{propname}", nil) unless (#{root}.has_key?("#{propname}"))
|
56
|
+
#{root}.fetch "#{propname}"
|
57
|
+
end
|
58
|
+
RUBY
|
59
|
+
end
|
60
|
+
|
61
|
+
def define_first_level_nesting_methods_for_subroot(root, subroot, subroot_type, propnames=nil)
|
62
|
+
subroot_value = case subroot_type.to_s
|
63
|
+
when "Array" then []
|
64
|
+
else {}
|
65
|
+
end
|
66
|
+
|
67
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
68
|
+
def #{subroot}
|
69
|
+
#{root}.store("#{subroot}", #{subroot_value}) unless (#{root}.has_key?("#{subroot}") and #{root}.fetch("#{subroot}").is_a?(#{subroot_value}.class))
|
70
|
+
#{root}.fetch "#{subroot}"
|
71
|
+
end
|
72
|
+
RUBY
|
73
|
+
|
74
|
+
if propnames
|
75
|
+
propnames.each do |a_propname|
|
76
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__+1
|
77
|
+
def #{subroot}_#{a_propname}=(val)
|
78
|
+
#{subroot}.store("#{a_propname}".to_s, val.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def #{subroot}_#{a_propname}
|
82
|
+
#{subroot}.store("#{a_propname}", nil) unless (#{subroot}.has_key?("#{a_propname}"))
|
83
|
+
#{subroot}.fetch "#{a_propname}".to_s
|
84
|
+
end
|
85
|
+
RUBY
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def define_second_level_nesting_methods(subroot, subsubroot, propnames)
|
91
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__+1
|
92
|
+
def #{subroot}_#{subsubroot}
|
93
|
+
#{subroot}.store("#{subsubroot}", {}) unless (#{subroot}.has_key?("#{subsubroot}") and #{subroot}.fetch("#{subsubroot}").is_a?(Hash))
|
94
|
+
#{subroot}.fetch "#{subsubroot}"
|
95
|
+
end
|
96
|
+
RUBY
|
97
|
+
|
98
|
+
if propnames
|
99
|
+
propnames.each do |a_propname|
|
100
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__+1
|
101
|
+
def #{subroot}_#{subsubroot}_#{a_propname}=(val)
|
102
|
+
#{subroot}_#{subsubroot}.store("#{a_propname}", val.to_s)
|
103
|
+
end
|
104
|
+
|
105
|
+
def #{subroot}_#{subsubroot}_#{a_propname}
|
106
|
+
#{subroot}_#{subsubroot}.store("#{a_propname}", nil) unless (#{subroot}_#{subsubroot}.has_key?("#{a_propname}"))
|
107
|
+
#{subroot}_#{subsubroot}.fetch "#{a_propname}"
|
108
|
+
end
|
109
|
+
RUBY
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/nested_accessors/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Oskar Boethius Lissheim"]
|
6
|
+
gem.email = ["oskar@OLBproductions.com"]
|
7
|
+
gem.homepage = "http://OLBproductions.com"
|
8
|
+
gem.description = %q{Quickly add serialized, nested hash accessors in ActiveRecord model objects}
|
9
|
+
gem.summary = %q{Without having to write your own accessor methods for getting at serialized hash properties}
|
10
|
+
gem.homepage = "http://OLBproductions.com"
|
11
|
+
gem.license = 'MIT'
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.name = "nested_accessors"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = NestedAccessors::VERSION
|
19
|
+
gem.extra_rdoc_files = ['README.md']
|
20
|
+
|
21
|
+
gem.add_development_dependency "minitest"
|
22
|
+
gem.add_development_dependency "simple_mock"
|
23
|
+
gem.add_development_dependency "minitest-colorize"
|
24
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/spec'
|
3
|
+
require 'simple_mock'
|
4
|
+
require 'minitest-colorize'
|
5
|
+
|
6
|
+
require_relative '../lib/nested_accessors'
|
7
|
+
|
8
|
+
# STUBBING OUT active_record "serialized" class method
|
9
|
+
class Person #< ActiveRecord::Base # must inherit from activerecord to get "serialize" class method
|
10
|
+
# Stubs out the "serialize :name, Hash" method
|
11
|
+
# So don't have to use activerecord
|
12
|
+
# Creates eg a :info hash accessor and returns hash
|
13
|
+
def self.serialize(name, klass)
|
14
|
+
attr_accessor name
|
15
|
+
define_method name do
|
16
|
+
@serialized_hash = {} if @serialized_hash.nil?
|
17
|
+
@serialized_hash
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# must include module after the serialize method has been defined (it's defined in the superclass when inherited from activerecord)
|
22
|
+
include NestedAccessors
|
23
|
+
|
24
|
+
# USAGE in active_record model:
|
25
|
+
# nested_accessor :info, :phone, address: [ :street, :zipcode ]
|
26
|
+
end
|
27
|
+
|
28
|
+
# SPECS
|
29
|
+
describe NestedAccessors do
|
30
|
+
describe 'init method for hash accessors' do
|
31
|
+
it 'should init root object to Hash if blank or not a Hash' do
|
32
|
+
Person.class_eval %q{ nested_accessor :info }
|
33
|
+
Person.new.info.class.must_equal Hash
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "with phone accessor" do
|
37
|
+
before(:each) do
|
38
|
+
Person.class_eval %q{ nested_accessor :info, :phone }
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:person) { Person.new }
|
42
|
+
|
43
|
+
it 'should use stringified keys' do
|
44
|
+
person.phone = "12378"
|
45
|
+
person.info.keys.must_include "phone"
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should init key to nil if blank' do
|
49
|
+
person.info.keys.must_be_empty
|
50
|
+
person.phone.must_be_nil # shouldn't raise exception since it couldn't find the key
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'sets up accessors for first level of nesting' do
|
54
|
+
person.phone = "123-2345"
|
55
|
+
person.phone.must_equal "123-2345"
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'read accessor should return value typed to String by default (to_s)' do
|
59
|
+
person.phone = 123
|
60
|
+
person.phone.must_equal "123"
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'write accessor should save value typed to String' do
|
64
|
+
person.phone = 234
|
65
|
+
person.info["phone"].must_equal "234"
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'each subvalue should be nil if regular value param' do
|
69
|
+
person.info["phone"].must_be_nil
|
70
|
+
person.info["address"].must_be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'can set multiple properties if first param is Array type' do
|
74
|
+
Person.class_eval %q{ nested_accessor :info, [:phone1, :phone2] }
|
75
|
+
person = Person.new
|
76
|
+
person.info["phone1"] = "2365"
|
77
|
+
person.phone1.must_equal "2365"
|
78
|
+
person.phone2 = "9090"
|
79
|
+
person.info["phone2"].must_equal "9090"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'subhashes' do
|
84
|
+
it 'should init as hash if gets Array with multiple params for a property name in Hash' do
|
85
|
+
# Gives self.info["address"]["street"] and ["city"]
|
86
|
+
Person.class_eval %q{ nested_accessor :info, address: [:street, :city] }
|
87
|
+
person = Person.new
|
88
|
+
person.address.must_be_kind_of Hash
|
89
|
+
person.address["city"] = "Goteborg"
|
90
|
+
person.address["city"].must_equal "Goteborg"
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should init subhash to nil value if blank' do
|
94
|
+
Person.class_eval %q{ nested_accessor :info, address: [:street, :city] }
|
95
|
+
person = Person.new
|
96
|
+
person.address.must_be_kind_of Hash
|
97
|
+
person.address_street.must_be_nil # shouldn't raise exception since it couldn't find the key
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should init with just one param in array' do
|
101
|
+
Person.class_eval %q{ nested_accessor :info, snub: [:identifier] }
|
102
|
+
person = Person.new
|
103
|
+
person.snub.must_be_kind_of Hash
|
104
|
+
person.snub_identifier = "Achaplan"
|
105
|
+
person.snub_identifier.must_equal "Achaplan"
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should init with just one param symbol in hash as well' do
|
109
|
+
Person.class_eval %q{ nested_accessor :info, auth: :facebook }
|
110
|
+
person = Person.new
|
111
|
+
person.auth.must_be_kind_of Hash
|
112
|
+
person.auth_facebook = "12k3j"
|
113
|
+
person.auth_facebook.must_equal "12k3j"
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should create shallow accessor methods for each hash propname' do
|
117
|
+
Person.class_eval %q{ nested_accessor :bank, branch: [:designator, :account_number] }
|
118
|
+
person = Person.new
|
119
|
+
person.branch.must_be_kind_of Hash
|
120
|
+
person.branch_designator = "123"
|
121
|
+
person.branch_designator.must_equal "123"
|
122
|
+
person.branch_account_number = "999"
|
123
|
+
person.branch_account_number.must_equal "999"
|
124
|
+
end
|
125
|
+
|
126
|
+
# it 'should perhaps create accessor methods on the subroot object, for each subparam in hash' do
|
127
|
+
# Person.class_eval %q{ nested_accessor :info, address: [:street, :city] }
|
128
|
+
# person = Person.new
|
129
|
+
# person.address.must_be_kind_of Hash
|
130
|
+
# # the subroot method must thus return an object and define attr_accessor methods on it for each propname
|
131
|
+
# person.address.street = "Storgatan"
|
132
|
+
# person.address.street.must_equal "Storgatan"
|
133
|
+
# person.address.city = "Bigtown"
|
134
|
+
# person.address.city.must_equal "Bigtown"
|
135
|
+
# end
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should init subvalue with Array if type set to array for accessor' do
|
139
|
+
# nested_accessor :info, balls: Array
|
140
|
+
#=> self.info["Balls"] == []
|
141
|
+
Person.class_eval %q{ nested_accessor :things, balls: Array }
|
142
|
+
person = Person.new
|
143
|
+
person.balls.must_be_kind_of Array
|
144
|
+
person.balls << "bob"
|
145
|
+
person.balls << "alice"
|
146
|
+
person.balls.must_include "bob"
|
147
|
+
person.balls.must_include "alice"
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'second level nesting' do
|
151
|
+
it 'sets up accessors for two level deep hash' do
|
152
|
+
# nested_accessor :info, subregion: { address: [:street, :city] }
|
153
|
+
#=> foo.info[address][subregion] = {}
|
154
|
+
# Person.class_eval %q{ nested_accessor :home, subregion: { address: [:street, :city] } }
|
155
|
+
Person.class_eval %q{ nested_accessor :home, budget: { heating: [:highest, :lowest] } }
|
156
|
+
person = Person.new
|
157
|
+
person.budget_heating.must_be_kind_of Hash
|
158
|
+
person.budget.must_be_kind_of Hash
|
159
|
+
person.budget.has_key?("heating").must_equal true # can only test that hash has the key after we've used the subregion command since that instantiates the nested hash
|
160
|
+
person.budget_heating_highest = "32 C"
|
161
|
+
person.budget_heating_highest.must_equal "32 C"
|
162
|
+
person.budget_heating_lowest = "10 C"
|
163
|
+
person.budget_heating_lowest.must_equal "10 C"
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should init deep hash values to nil value if blank' do
|
167
|
+
Person.class_eval %q{ nested_accessor :place, location: { coordinate: [:lat, :lon] } }
|
168
|
+
person = Person.new
|
169
|
+
person.location_coordinate.must_be_kind_of Hash
|
170
|
+
person.location_coordinate_lat.must_be_nil # shouldn't raise exception since it couldn't find the key
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should set deep hash values and not overwrite others in the same subhash' do
|
174
|
+
# TODO: Must test so we don't just write a new hash when changing a value
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nested_accessors
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Oskar Boethius Lissheim
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: simple_mock
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-colorize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Quickly add serialized, nested hash accessors in ActiveRecord model objects
|
56
|
+
email:
|
57
|
+
- oskar@OLBproductions.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files:
|
61
|
+
- README.md
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/nested_accessors.rb
|
69
|
+
- lib/nested_accessors/railtie.rb
|
70
|
+
- lib/nested_accessors/version.rb
|
71
|
+
- nested_accessors.gemspec
|
72
|
+
- spec/nested_accessors_spec.rb
|
73
|
+
homepage: http://OLBproductions.com
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.0.3
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: Without having to write your own accessor methods for getting at serialized
|
97
|
+
hash properties
|
98
|
+
test_files:
|
99
|
+
- spec/nested_accessors_spec.rb
|