hash-ninja 0.1.0

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