hash-ninja 0.1.0

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.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea
6
+ doc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'activesupport'
4
+ gem 'rspec'
5
+
6
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "hash_ninja/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "hash-ninja"
7
+ s.version = HashNinja::VERSION
8
+ s.authors = ["Kazuhiro Sera"]
9
+ s.email = ["seratch@gmail.com"]
10
+ s.homepage = "https://github.com/seratch/hash-ninja"
11
+ s.summary = %q{Hash toolkit for Ruby ninja}
12
+ s.description = %q{Hash toolkit for Ruby ninja}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_runtime_dependency "activesupport"
20
+
21
+ end
@@ -0,0 +1,10 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "hash_ninja/active_hash"
4
+ require "hash_ninja/core_ext"
5
+ require "hash_ninja/hash_attr_reader"
6
+ require "hash_ninja/version"
7
+
8
+ # HashNinja is a useful utility library for Ruby Hash
9
+ module HashNinja
10
+ end
@@ -0,0 +1,127 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "hash_ninja"
4
+ require "active_support/core_ext/hash/keys"
5
+
6
+ module HashNinja
7
+
8
+ # Hash with extended ActiveSupport
9
+ #
10
+ # See also {active_support/core_ext/hash/keys}[http://as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/Keys.html]
11
+ module ActiveHash
12
+
13
+ # Applies ActiveSupport::Inflector.underscore to all the Hash#keys destructively.
14
+ # Keys should be either Symbol or String.
15
+ #
16
+ # ==== Examples
17
+ # hash = {:rubyOnRails => 'http://rubyonrails.org/'}
18
+ # has.activate!.underscore_keys! # => {:ruby_on_rails => 'http://rubyonrails.org/'}
19
+ def underscore_keys!
20
+ self.keys.each do |key|
21
+ value = delete(key)
22
+ if key.is_a? String
23
+ self[key.underscore] = value
24
+ elsif key.is_a? Symbol
25
+ self[key.to_s.underscore.to_sym] = value
26
+ end
27
+ end
28
+ self
29
+ end
30
+
31
+ # Applies ActiveSupport::Inflector#classify to all the Hash#keys destructively.
32
+ # Keys should be either Symbol or String.
33
+ #
34
+ # ==== Examples
35
+ # hash = {:ruby_on_rails => 'http://rubyonrails.org/'}
36
+ # has.activate!.classify_keys! # => {:RubyOnRails => 'http://rubyonrails.org/'}
37
+ def classify_keys!
38
+ self.keys.each do |key|
39
+ value = delete(key)
40
+ if key.is_a? String
41
+ self[key.classify] = value
42
+ elsif key.is_a? Symbol
43
+ self[key.to_s.classify.to_sym] = value
44
+ end
45
+ end
46
+ end
47
+
48
+ # Applies ActiveSupport::Inflector#camelize to all the Hash#keys destructively.
49
+ # Keys should be either Symbol or String.
50
+ #
51
+ # ==== Examples
52
+ # hash = {:ruby_on_rails => 'http://rubyonrails.org/'}
53
+ # has.activate!.camelize_keys! # => {:RubyOnRails => 'http://rubyonrails.org/'}
54
+ def camelize_keys!
55
+ self.keys.each do |key|
56
+ value = delete(key)
57
+ if key.is_a? String
58
+ self[key.camelize] = value
59
+ elsif key.is_a? Symbol
60
+ self[key.to_s.camelize.to_sym] = value
61
+ end
62
+ end
63
+ end
64
+
65
+ #
66
+ # Applies ActiveSupport::Inflector#camelize(:lower) to all the Hash#keys destructively.
67
+ # Keys should be either Symbol or String.
68
+ #
69
+ # ==== Examples
70
+ # hash = {:ruby_on_rails => 'http://rubyonrails.org/'}
71
+ # has.activate!.camelize_lower_keys! # => {:rubyOnRails => 'http://rubyonrails.org/'}
72
+ def camelize_lower_keys!
73
+ self.keys.each do |key|
74
+ value = delete(key)
75
+ if key.is_a? String
76
+ self[key.camelize(:lower)] = value
77
+ elsif key.is_a? Symbol
78
+ self[key.to_s.camelize(:lower).to_sym] = value
79
+ end
80
+ end
81
+ end
82
+
83
+ # Provides the following recursive methods.
84
+ #
85
+ # ====
86
+ # * recursively_camelize_keys!
87
+ # * recursively_camelize_lower_keys!
88
+ # * recursively_classify_keys!
89
+ # * recursively_underscore_keys!
90
+ def method_missing(name, *args, &block)
91
+ # provides 'recursively_xxx' methods
92
+ if name.match(/recursively_/)
93
+ method_name = name.to_s.sub(/^recursively_/, '')
94
+ self.public_send(method_name, *args, &block)
95
+ self.values.each do |value|
96
+ if value.is_a? Hash
97
+ value.extend HashNinja::ActiveHash
98
+ value.public_send(name, *args, &block)
99
+ elsif value.is_a? Array
100
+ value.public_send(name, *args, &block)
101
+ end
102
+ end
103
+ self
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+
110
+ class Array
111
+ def method_missing(name, *args, &block)
112
+ # for ActiveHash#recursively_xxx
113
+ if name.match(/recursively_/)
114
+ method_name = name.to_s.sub(/^recursively_/, '')
115
+ self.each do |value|
116
+ if value.is_a? Hash
117
+ value.extend HashNinja::ActiveHash
118
+ value.public_send(name, *args, &block)
119
+ elsif value.is_a? Array
120
+ value.public_send(name, *args, &block)
121
+ end
122
+ end
123
+ self
124
+ end
125
+ end
126
+ end
127
+
@@ -0,0 +1,50 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "hash_ninja"
4
+ require "active_support/core_ext/string/inflections"
5
+
6
+ module HashNinja
7
+ module CoreExt
8
+ end
9
+ end
10
+
11
+ class Hash
12
+
13
+ # Updates itself as HashNinja::ActiveHash destructively. 'active_support' will be also applied.
14
+ def activate!
15
+ self.extend HashNinja::ActiveHash
16
+ self
17
+ end
18
+
19
+ # Provides HashNinja::HashAccessor object
20
+ def to_attr_reader
21
+ HashNinja::HashAttrReader.new(self)
22
+ end
23
+
24
+ # Creates Hash object which contains the readable instance variables of 'obj'.
25
+ # It's possible to customize the key convention by 'key_strategy'.
26
+ def self.from_attr(obj, key_strategy = :underscore)
27
+ hash = {}
28
+ obj.instance_variables.each do |attr|
29
+ original_key = attr.to_s.delete('@')
30
+ case key_strategy
31
+ when :underscore
32
+ key = original_key.underscore
33
+ when :camelize
34
+ key = original_key.camelize
35
+ when :camelize_lower
36
+ key = original_key.camelize(:lower)
37
+ when :classify
38
+ key = original_key.classify
39
+ else
40
+ key = original_key
41
+ end
42
+ begin
43
+ hash[key.to_sym] = obj.send(original_key.to_sym)
44
+ rescue NoMethodError => e
45
+ end
46
+ end
47
+ hash
48
+ end
49
+
50
+ end
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module HashNinja
4
+
5
+ # Provides attr_reader Hash data
6
+ # ==== Examples
7
+ # member = {'name'=>'Andy', 'type' => { 'id' => 999, 'name' => 'Guest' }}.to_attr_reader
8
+ # member.name # => 'Andy'
9
+ # member.type.id # => 999
10
+ class HashAttrReader
11
+ # target Hash object
12
+ attr_reader :hash
13
+
14
+ # The 'hash' should be a Hash object.
15
+ def initialize(hash)
16
+ raise "hash should be a Hash object #{hash.to_s}" unless hash.is_a? Hash
17
+ @hash = hash
18
+ end
19
+
20
+ def method_missing(name, *args, &block)
21
+ found = @hash[name] || @hash[name.to_s]
22
+ if found
23
+ if found.is_a? Hash
24
+ found.to_attr_reader
25
+ else
26
+ found
27
+ end
28
+ end
29
+ end
30
+
31
+ # Returns the Hash object held internally
32
+ def to_hash
33
+ @hash
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module HashNinja
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'active_support'
4
+ require 'hash_ninja'
5
+
6
+ describe HashNinja::ActiveHash do
7
+
8
+ it 'should have #underscore_keys!' do
9
+ hash = {:rubyOnRails => 'xxx', 'ProgrammingRuby' => {'RubyGems' => 'yyy'}}
10
+ hash.activate!.underscore_keys!
11
+
12
+ hash[:ruby_on_rails].should eq('xxx')
13
+ hash['programming_ruby'].should eq({'RubyGems' => 'yyy'})
14
+ end
15
+
16
+ it 'should have #recursively_underscore_keys!' do
17
+ hash = {:rubyOnRails => 'aaa', 'ProgrammingRuby' => {:RubyGems => 'bbb', 'rubyMine' => 'ccc'}}
18
+ hash.activate!.recursively_underscore_keys!
19
+
20
+ hash[:ruby_on_rails].should eq('aaa')
21
+ hash['programming_ruby'].should eq({:ruby_gems => 'bbb', 'ruby_mine' => 'ccc'})
22
+ hash['programming_ruby'][:ruby_gems].should eq('bbb')
23
+ hash['programming_ruby']['ruby_mine'].should eq('ccc')
24
+ end
25
+
26
+ end
@@ -0,0 +1,86 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'hash_ninja'
4
+
5
+ describe Hash do
6
+
7
+ it 'should have #activate!' do
8
+ activated = {:first => 'aaa', 'second' => 'bbb'}.activate!
9
+ activated.is_a?(HashNinja::ActiveHash).should eq(true)
10
+ end
11
+
12
+ class Member
13
+ attr_accessor :id
14
+ attr_accessor :name
15
+ attr_accessor :age
16
+
17
+ def initialize(id, name, age)
18
+ @id = id
19
+ @name = name
20
+ @age = age
21
+ end
22
+ end
23
+
24
+ class Member2Underscore
25
+ attr_accessor :firstName
26
+ attr_accessor :lastName
27
+
28
+ def initialize(firstName, lastName)
29
+ @firstName = firstName
30
+ @lastName = lastName
31
+ end
32
+ end
33
+
34
+ class Member2Camelize
35
+ attr_accessor :first_name
36
+ attr_accessor :last_name
37
+
38
+ def initialize(first_name, last_name)
39
+ @first_name = first_name
40
+ @last_name = last_name
41
+ end
42
+ end
43
+
44
+ it 'shoud have from_attr' do
45
+ andy = Member.new(123, 'Andy', 20)
46
+ andy_hash = Hash.from_attr(andy)
47
+ andy_hash[:id].should eq(123)
48
+ andy_hash[:name].should eq('Andy')
49
+ andy_hash[:age].should eq(20)
50
+
51
+ brian = Member.new(123, 'Brian', nil)
52
+ brian_hash = Hash.from_attr(brian)
53
+ brian_hash[:id].should eq(123)
54
+ brian_hash[:name].should eq('Brian')
55
+ brian_hash[:age].should eq(nil)
56
+ end
57
+
58
+ it 'should have from_attr (underscore)' do
59
+ m = Member2Underscore.new('Linus', 'Torvalds')
60
+ hash = Hash.from_attr(m, :underscore)
61
+ hash[:first_name].should eq('Linus')
62
+ hash[:last_name].should eq('Torvalds')
63
+ end
64
+
65
+ it 'should have from_attr (camelize)' do
66
+ m = Member2Camelize.new('Linus', 'Torvalds')
67
+ hash = Hash.from_attr(m, :camelize)
68
+ hash[:FirstName].should eq('Linus')
69
+ hash[:LastName].should eq('Torvalds')
70
+ end
71
+
72
+ it 'should have from_attr (camelize_lower)' do
73
+ m = Member2Camelize.new('Linus', 'Torvalds')
74
+ hash = Hash.from_attr(m, :camelize_lower)
75
+ hash[:firstName].should eq('Linus')
76
+ hash[:lastName].should eq('Torvalds')
77
+ end
78
+
79
+ it 'should have from_attr (classify)' do
80
+ m = Member2Camelize.new('Linus', 'Torvalds')
81
+ hash = Hash.from_attr(m, :classify)
82
+ hash[:FirstName].should eq('Linus')
83
+ hash[:LastName].should eq('Torvalds')
84
+ end
85
+
86
+ end
@@ -0,0 +1,66 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "hash_ninja"
4
+
5
+ describe HashNinja::HashAttrReader do
6
+
7
+ it 'should work with string keys' do
8
+ hash = {:something => 'like that', :name => 'hash_ninja'}
9
+ hash_attr = hash.to_attr_reader
10
+
11
+ hash_attr.something.should eq('like that')
12
+ hash_attr.name.should eq('hash_ninja')
13
+ end
14
+
15
+ it 'should work with symbol keys' do
16
+ hash = {:something => 'like that', :name => 'hash_ninja'}
17
+ hash_attr = hash.to_attr_reader
18
+
19
+ hash_attr.something.should eq('like that')
20
+ hash_attr.name.should eq('hash_ninja')
21
+ end
22
+
23
+ it 'should work with nested hash' do
24
+ hash = {
25
+ :something => 'like that',
26
+ :nested => {
27
+ :name => 'hash_ninja',
28
+ :since => 2012
29
+ }
30
+ }
31
+ hash_attr = hash.to_attr_reader
32
+
33
+ hash_attr.something.should eq('like that')
34
+ hash_attr.nested.name.should eq('hash_ninja')
35
+ hash_attr.nested.since.should eq(2012)
36
+ end
37
+
38
+ it 'should work with keys which contains whitespace' do
39
+ hash = {'contains whitespace' => 'like that'}
40
+ hash_attr = hash.to_attr_reader
41
+
42
+ hash_attr.contains_whitespace.should eq(nil)
43
+ end
44
+
45
+ it 'should work with string keys' do
46
+ hash = {'something' => 'like that', 'name' => 'hash_ninja'}
47
+ hash_attr = hash.to_attr_reader
48
+
49
+ hash_attr.something.should eq('like that')
50
+ hash_attr.name.should eq('hash_ninja')
51
+ end
52
+
53
+ it 'should work with array' do
54
+ hash = {
55
+ 'str_array' => ['a', 'b', 'c'],
56
+ 'hash_array' => [{:a => 1}, {:aa => 1, :bb => 2}],
57
+ 'nested' => {'array' => [1, 2, 3]}
58
+ }
59
+ hash_attr = hash.to_attr_reader
60
+
61
+ hash_attr.str_array.should eq(['a', 'b', 'c'])
62
+ hash_attr.hash_array.should eq([{:a => 1}, {:aa => 1, :bb => 2}])
63
+ hash_attr.nested.array.should eq([1, 2, 3])
64
+ end
65
+
66
+ end
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'active_support'
4
+ require 'hash_ninja'
5
+
6
+ describe HashNinja do
7
+
8
+ it 'should work with the Google+ API example data' do
9
+ google_plus_api_example = <<JSON
10
+ {
11
+ "kind": "plus#person",
12
+ "id": "118051310819094153327",
13
+ "displayName": "Chirag Shah",
14
+ "url": "https://plus.google.com/118051310819094153327",
15
+ "image": {
16
+ "url": "https://lh5.googleusercontent.com/-XnZDEoiF09Y/AAAAAAAAAAI/AAAAAAAAYCI/7fow4a2UTMU/photo.jpg"
17
+ }
18
+ }
19
+ JSON
20
+
21
+ hash = ActiveSupport::JSON.decode(google_plus_api_example)
22
+ hash.activate!
23
+
24
+ hash.recursively_underscore_keys!
25
+ hash['kind'].should eq('plus#person')
26
+ hash['id'].should eq('118051310819094153327')
27
+ hash['display_name'].should eq('Chirag Shah')
28
+ hash['url'].should eq('https://plus.google.com/118051310819094153327')
29
+ hash['image']['url'].should eq('https://lh5.googleusercontent.com/-XnZDEoiF09Y/AAAAAAAAAAI/AAAAAAAAYCI/7fow4a2UTMU/photo.jpg')
30
+
31
+ hash.recursively_symbolize_keys!
32
+ hash[:kind].should eq('plus#person')
33
+ hash[:id].should eq('118051310819094153327')
34
+ hash[:display_name].should eq('Chirag Shah')
35
+ hash[:url].should eq('https://plus.google.com/118051310819094153327')
36
+ hash[:image][:url].should eq('https://lh5.googleusercontent.com/-XnZDEoiF09Y/AAAAAAAAAAI/AAAAAAAAYCI/7fow4a2UTMU/photo.jpg')
37
+
38
+ hash_attr = hash.to_attr_reader
39
+ hash_attr.kind.should eq('plus#person')
40
+ hash_attr.id.should eq('118051310819094153327')
41
+ hash_attr.display_name.should eq('Chirag Shah')
42
+ hash_attr.url.should eq('https://plus.google.com/118051310819094153327')
43
+ hash_attr.image.url.should eq('https://lh5.googleusercontent.com/-XnZDEoiF09Y/AAAAAAAAAAI/AAAAAAAAYCI/7fow4a2UTMU/photo.jpg')
44
+ end
45
+
46
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash-ninja
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kazuhiro Sera
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Hash toolkit for Ruby ninja
31
+ email:
32
+ - seratch@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - Rakefile
40
+ - hashninja.gemspec
41
+ - lib/hash_ninja.rb
42
+ - lib/hash_ninja/active_hash.rb
43
+ - lib/hash_ninja/core_ext.rb
44
+ - lib/hash_ninja/hash_attr_reader.rb
45
+ - lib/hash_ninja/version.rb
46
+ - spec/hash_ninja/active_hash_spec.rb
47
+ - spec/hash_ninja/core_ext_spec.rb
48
+ - spec/hash_ninja/hash_attr_reader_spec.rb
49
+ - spec/hash_ninja/usage_spec.rb
50
+ homepage: https://github.com/seratch/hash-ninja
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.21
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Hash toolkit for Ruby ninja
74
+ test_files:
75
+ - spec/hash_ninja/active_hash_spec.rb
76
+ - spec/hash_ninja/core_ext_spec.rb
77
+ - spec/hash_ninja/hash_attr_reader_spec.rb
78
+ - spec/hash_ninja/usage_spec.rb