methodize 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ Methodize
2
+ ---------
3
+
4
+ Is a module to read from and write to the keys of a ruby Hash using methods. As simple as this:
5
+
6
+ require 'methodize/hash'
7
+ hash.methodize!
8
+
9
+ If you don't want to mess with your Hash class, just do this:
10
+
11
+ require 'methodize'
12
+ hash.extend(Methodize)
13
+
14
+ The advantage of using Methodize is that you can easily access the values of complex or big Hash objects, such as converted JSONs returned from Web Services, RESTful APIs, etc.
15
+
16
+ Instead of using:
17
+
18
+ hash["article"].last["info"][:category].first
19
+
20
+ You can use:
21
+
22
+ hash.article.last.info.category.first
23
+
24
+ ### Interested? Let's see more examples ###
25
+
26
+ Let's suppose that we have the following hash object:
27
+
28
+ hash = {
29
+ :article => [
30
+ {
31
+ :title => "Article 1",
32
+ :author => "John Doe",
33
+ :url => "http://a.url.com"
34
+ },{
35
+ "title" => "Article 2",
36
+ "author" => "Foo Bar",
37
+ "url" => "http://another.url.com"
38
+ },{
39
+ :title => "Article 3",
40
+ :author => "Biff Tannen",
41
+ :url => ["http://yet.another.url.com", "http://localhost"],
42
+ :info => {
43
+ :published => "2010-05-31",
44
+ :category => [:sports, :entertainment]
45
+ }
46
+ }
47
+ ],
48
+ "type" => :text,
49
+ :size => 3,
50
+ :id => 123456789
51
+ }
52
+
53
+ You can change the **title of the third article** using:
54
+
55
+ hash.article[2].title = "New title"
56
+ hash.article[2].title # => "New title"
57
+
58
+ Hash public methods that conflicts with keys will be automatically freed:
59
+
60
+ hash.type # => :text
61
+ hash.size # => 3
62
+ hash.id # => 123456789
63
+
64
+ But don't panic, you can still use the Hash methods just as Ruby does for id and send methods by default:
65
+
66
+ hash.__type__ # => Hash
67
+ hash.__size__ # => 4 (hash keys count)
68
+
69
+ ### Another examples ###
70
+
71
+ Writing:
72
+
73
+ hash.article.last.title = "Article 3"
74
+ hash.article[1].info = {
75
+ :published => "2010-08-31",
76
+ :category => [:sports, :entertainment]
77
+ }
78
+ hash.article << {
79
+ :title => "A new title",
80
+ :author => "Marty Mcfly"
81
+ }
82
+ hash.shift = 12
83
+ hash["inspect"] = false
84
+ hash.size = 4
85
+
86
+ Accessing:
87
+
88
+ hash.article[2].title # => "Article 3"
89
+ hash.article[1].info.published # => "2010-08-31"
90
+ hash.article.last.author # => "Marty Mcfly"
91
+ hash.shift # => 12
92
+ hash.inspect # => false
93
+ hash.__inspect__.class # => String
94
+ hash.size # => 4
95
+ hash.__size__ # => 6
96
+
97
+ You can access the Hash as usual using [] or []=.
98
+
99
+ Check the tests for more examples.
100
+
101
+ *Created by Luis Cipriani*<br/>
102
+ *http://blog.talleye.com*
@@ -0,0 +1,58 @@
1
+ module Methodize
2
+ def self.extended(base)
3
+ # if some of the Hash keys and public methods names conflict
4
+ # we free the existant method to enable the user to call it
5
+ base.keys.each do |k|
6
+ base.__free_method__(k.to_sym) if base.public_methods.include?(k.to_s)
7
+ end
8
+ end
9
+
10
+ def [](key)
11
+ __normalize__(super(key))
12
+ end
13
+
14
+ def []=(key, value)
15
+ __free_method__(key) if !self.keys.include?(key) && self.public_methods.include?(key.to_s)
16
+ super(key,value)
17
+ end
18
+
19
+ def method_missing(name, *args)
20
+ method_name = name.to_s
21
+ if method_name[-1,1] == '='
22
+ method_name = method_name.chop
23
+ self.key?(method_name) ? key = method_name : key = method_name.to_sym
24
+ self[key] = args[0]
25
+ else
26
+ self.key?(method_name) ? key = method_name : key = method_name.to_sym
27
+ self[key]
28
+ end
29
+ end
30
+
31
+ # if you have a key that is also a method (such as Array#size)
32
+ # you can use this to free the method and use the method obj.size
33
+ # to access the value of key "size".
34
+ # you still can access the old method with __[method_name]__
35
+ def __free_method__(sym)
36
+ self.__metaclass__.send(:alias_method, "__#{sym.to_s}__".to_sym, sym) unless self.respond_to?("__#{sym.to_s}__")
37
+ self.__metaclass__.send(:define_method, sym) { method_missing(sym.to_s) }
38
+ self
39
+ end
40
+
41
+ def __metaclass__
42
+ class << self; self; end
43
+ end
44
+
45
+ private
46
+
47
+ def __normalize__(value)
48
+ case value
49
+ when Hash
50
+ value.extend(Methodize)
51
+ when Array
52
+ value.map { |v| __normalize__(v) }
53
+ else
54
+ value
55
+ end
56
+ value
57
+ end
58
+ end
@@ -0,0 +1,6 @@
1
+ require 'methodize'
2
+ class Hash
3
+ def methodize!
4
+ self.extend(Methodize)
5
+ end
6
+ end
@@ -0,0 +1,64 @@
1
+ require 'test/unit'
2
+ require 'methodize/hash'
3
+
4
+ require 'rubygems'
5
+ require 'ruby-debug'
6
+
7
+ class MethodizeTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @hash = {
11
+ :article => [
12
+ {
13
+ :title => "Article 1",
14
+ :author => "John Doe",
15
+ :url => "http://a.url.com"
16
+ },{
17
+ "title" => "Article 2",
18
+ "author" => "Foo Bar",
19
+ "url" => "http://another.url.com"
20
+ },{
21
+ :title => "Article 3",
22
+ :author => "Biff Tannen",
23
+ :url => ["http://yet.another.url.com", "http://localhost"],
24
+ :info => {
25
+ :published => "2010-05-31",
26
+ :category => [:sports, :entertainment]
27
+ }
28
+ }
29
+ ],
30
+ "type" => :text,
31
+ :size => 3,
32
+ :id => 123456789
33
+ }
34
+
35
+ @hash.methodize!
36
+ end
37
+
38
+ def test_methodize_should_still_work_as_expected
39
+ assert_equal @hash[:article].last[:title], "Article 3"
40
+ assert_equal @hash[:article][1]["author"], "Foo Bar"
41
+ assert_equal @hash["type"] , :text
42
+ assert_equal @hash[:size] , 3
43
+ assert_nil @hash[:wrong_key]
44
+
45
+ assert @hash.keys.include?(:size)
46
+ assert_equal @hash.article.size, 3
47
+ end
48
+
49
+ def test_methodize_should_support_read_of_values_as_methods
50
+ assert_equal @hash.article.last.title , "Article 3"
51
+ assert_equal @hash.article[1].author , "Foo Bar"
52
+ assert_equal @hash.article.last.info.category.first, :sports
53
+ assert_nil @hash.wrong_key
54
+
55
+ assert_equal @hash.size, 3
56
+ assert_equal @hash.type, :text
57
+ assert_equal @hash.id , 123456789
58
+ end
59
+
60
+ def test_double_methodize_call_does_not_affect_anything
61
+ assert_equal @hash.methodize!.article.last.title, "Article 3"
62
+ end
63
+
64
+ end
@@ -0,0 +1,98 @@
1
+ require 'test/unit'
2
+ require 'methodize'
3
+
4
+ require 'rubygems'
5
+ require 'ruby-debug'
6
+
7
+ class MethodizeTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @hash = {
11
+ :article => [
12
+ {
13
+ :title => "Article 1",
14
+ :author => "John Doe",
15
+ :url => "http://a.url.com"
16
+ },{
17
+ "title" => "Article 2",
18
+ "author" => "Foo Bar",
19
+ "url" => "http://another.url.com"
20
+ },{
21
+ :title => "Article 3",
22
+ :author => "Biff Tannen",
23
+ :url => ["http://yet.another.url.com", "http://localhost"],
24
+ :info => {
25
+ :published => "2010-05-31",
26
+ :category => [:sports, :entertainment]
27
+ }
28
+ }
29
+ ],
30
+ "type" => :text,
31
+ :size => 3,
32
+ :id => 123456789
33
+ }
34
+
35
+ @hash.extend(Methodize)
36
+ end
37
+
38
+ def test_hash_should_still_work_as_expected
39
+ assert_equal @hash[:article].last[:title], "Article 3"
40
+ assert_equal @hash[:article][1]["author"], "Foo Bar"
41
+ assert_equal @hash["type"] , :text
42
+ assert_equal @hash[:size] , 3
43
+ assert_nil @hash[:wrong_key]
44
+
45
+ assert @hash.keys.include?(:size)
46
+ assert_equal @hash.article.size, 3
47
+ end
48
+
49
+ def test_hash_should_support_read_of_values_as_methods
50
+ assert_equal @hash.article.last.title , "Article 3"
51
+ assert_equal @hash.article[1].author , "Foo Bar"
52
+ assert_equal @hash.article.last.info.category.first, :sports
53
+ assert_nil @hash.wrong_key
54
+ end
55
+
56
+ def test_should_free_existant_methods_by_default
57
+ assert_equal @hash.size, 3
58
+ assert_equal @hash.type, :text
59
+ assert_equal @hash.id , 123456789
60
+ end
61
+
62
+ def test_should_be_able_to_call_previously_freed_methods
63
+ assert_equal @hash.__size__, 4
64
+ begin #avoid showing deprecate Object#type warning on test log
65
+ $stderr = StringIO.new
66
+ assert_equal @hash.__type__, Hash
67
+ $stderr.rewind
68
+ ensure
69
+ $stderr = STDERR
70
+ end
71
+ assert_not_equal @hash.__id__ , 123456789
72
+ end
73
+
74
+ def test_should_enable_write_operations
75
+ @hash.article.last.title = "Article 3"
76
+ @hash.article[1].info = {
77
+ :published => "2010-08-31",
78
+ :category => [:sports, :entertainment]
79
+ }
80
+ @hash.article << {
81
+ :title => "A new title",
82
+ :author => "Marty Mcfly"
83
+ }
84
+ @hash.shift = 12
85
+ @hash["inspect"] = false
86
+ @hash.size = 4
87
+
88
+ assert_equal @hash.article[2].title , "Article 3"
89
+ assert_equal @hash.article[1].info.published, "2010-08-31"
90
+ assert_equal @hash.article.last.author , "Marty Mcfly"
91
+ assert_equal @hash.shift , 12
92
+ assert_equal @hash.inspect , false
93
+ assert_equal @hash.__inspect__.class , String
94
+ assert_equal @hash.size , 4
95
+ assert_equal @hash.__size__ , 6
96
+ end
97
+ end
98
+
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: methodize
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Luis Cipriani
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-06-01 00:00:00 -03:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: lfcipriani@talleye.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README.md
26
+ - lib/methodize.rb
27
+ - lib/methodize/hash.rb
28
+ - test/methodize_test.rb
29
+ - test/hash_test.rb
30
+ has_rdoc: true
31
+ homepage: http://blog.talleye.com
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project:
54
+ rubygems_version: 1.3.5
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: Module to read from and write to the keys of a ruby Hash using methods
58
+ test_files: []
59
+