hashstruct 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +69 -0
- data/lib/hashstruct.rb +89 -0
- metadata +49 -0
data/README.mdown
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
HashStruct provides an object based on Hash, but acts like Struct (or OpenStruct), providing helpful
|
2
|
+
accessors for each key from the get-go. It also magically parses string values when it can (eg, dates,
|
3
|
+
URIs, numbers, and does so recursively.
|
4
|
+
|
5
|
+
You can use HashStruct as a first-class object like this:
|
6
|
+
|
7
|
+
h = HashStruct.new
|
8
|
+
h.foo = 1
|
9
|
+
h.bar = 'zot'
|
10
|
+
|
11
|
+
Or you can pass it a hash of existing values:
|
12
|
+
|
13
|
+
h = HashStruct.new(
|
14
|
+
:foo => 1,
|
15
|
+
:bar => 'z')
|
16
|
+
|
17
|
+
Or simply an existing hash:
|
18
|
+
|
19
|
+
thing = { :foo => 1, :bar => 'z' }
|
20
|
+
h = HashStruct.new(thing)
|
21
|
+
|
22
|
+
Or because it's a Hash underneath, you can use the '[]' construction method:
|
23
|
+
|
24
|
+
h = HashStruct[
|
25
|
+
[:foo, 1], [:bar, 'z']
|
26
|
+
]
|
27
|
+
|
28
|
+
Or a combination:
|
29
|
+
|
30
|
+
h = HashStruct.new(
|
31
|
+
:foo => 1,
|
32
|
+
:bar => 'z')
|
33
|
+
h.zot = :x
|
34
|
+
|
35
|
+
HashStruct magically converts any values from strings (and sub-arrays/hashes) to native objects, when it can. Like so:
|
36
|
+
|
37
|
+
h = HashStruct.new(
|
38
|
+
:an_int => '1', # => 1
|
39
|
+
:a_float => '1.5', # => 1.5
|
40
|
+
:a_url => 'http://foo.com/bar', # => #<URI::HTTP:0x000001009c6160 URL:http://foo.com/bar>
|
41
|
+
:a_date => '2008-01-02', # => #<DateTime: 2008-01-02T00:00:00+00:00 (4908935/2,0/1,2299161)>
|
42
|
+
:a_date_time => '2011-06-17 09:36:49 -0700', # => #<DateTime: 2011-06-17T09:36:49-07:00 (212175088609/86400,-7/24,2299161)>
|
43
|
+
:a_bool_true => 'true', # => true
|
44
|
+
:a_bool_false => 'false', # => false
|
45
|
+
:a_percentage => '50%', # => 0.5
|
46
|
+
:an_int_array => %w{1 2 3}, # => [1, 2, 3]
|
47
|
+
)
|
48
|
+
|
49
|
+
You can't turn off the magical conversion. (Secret: you could monkey-patch `#convert_value` to
|
50
|
+
simply return the passed-in object.)
|
51
|
+
|
52
|
+
You can also easily subclass HashStruct. You can add helper methods if needed, or accessor methods,
|
53
|
+
which will be noticed and used by HashStruct. Note that any additional instance variables are not treated
|
54
|
+
as part of the structure.
|
55
|
+
|
56
|
+
class Thing < HashStruct
|
57
|
+
|
58
|
+
attr_accessor :mul
|
59
|
+
|
60
|
+
def foo_mul
|
61
|
+
self.foo * @mul
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
t = Thing.new
|
67
|
+
t.foo = 2
|
68
|
+
t.mul = 2
|
69
|
+
t.foo_mul # => 4
|
data/lib/hashstruct.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class HashStruct < Hash
|
5
|
+
|
6
|
+
VERSION = '1.0.0'
|
7
|
+
|
8
|
+
def initialize(args={})
|
9
|
+
super()
|
10
|
+
args.each { |key, value| self[key] = value }
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
key = key.to_sym
|
15
|
+
if methods.include?(key)
|
16
|
+
method(key).call
|
17
|
+
elsif has_key?(key)
|
18
|
+
fetch(key)
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(key, value)
|
25
|
+
if methods.include?(:"#{key}=")
|
26
|
+
method(:"#{key}=").call(convert_object(value))
|
27
|
+
else
|
28
|
+
store(key.to_s.to_sym, convert_object(value))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(method_id, *args)
|
33
|
+
method_name = method_id.to_s
|
34
|
+
if method_name =~ /=$/
|
35
|
+
raise ArgumentError, "wrong number of arguments for method #{method_name.inspect} (#{args.length} for 1)", caller(1) if args.length != 1
|
36
|
+
raise TypeError, "can't modify frozen #{self.class}", caller(1) if self.frozen?
|
37
|
+
self[method_name.chop.to_sym] = args.first
|
38
|
+
else
|
39
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 0)", caller(1) if args.length != 0
|
40
|
+
self[method_id]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def convert_object(obj)
|
45
|
+
case obj
|
46
|
+
when String
|
47
|
+
case obj
|
48
|
+
# URI
|
49
|
+
when %r{^(ftp|http|https|mailto):}
|
50
|
+
URI.parse(obj) rescue obj
|
51
|
+
# integer
|
52
|
+
when %r{^-?[1-9][\d,]*$}
|
53
|
+
obj.gsub(/,/, '').to_i
|
54
|
+
# hex integer
|
55
|
+
when %r{^0x[0-9a-f]+$}i
|
56
|
+
obj.hex
|
57
|
+
# float
|
58
|
+
when %r{^-?[\d,]+\.\d+$}
|
59
|
+
obj.gsub(/,/, '').to_f
|
60
|
+
# percent
|
61
|
+
when %r{^-?[\d,]+(\.\d+)?%$}
|
62
|
+
obj.to_f / 100
|
63
|
+
# date
|
64
|
+
when %r{^\d{4}-\d{2}-\d{2}}, # 2010-06-06
|
65
|
+
%r{^\d{1,2}/\d{1,2}/\d{4}}, # 06/06/2010
|
66
|
+
%r{^\d{4}/\d{1,2}/\d{1,2}}, # 2010/06/06
|
67
|
+
%r{^(Sun|Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s*\d*\s*\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b} # Sun, 06 Jun 2010 23:02:25 GMT
|
68
|
+
DateTime.parse(obj)
|
69
|
+
# boolean true
|
70
|
+
when 'true'
|
71
|
+
true
|
72
|
+
# boolean false
|
73
|
+
when 'false'
|
74
|
+
false
|
75
|
+
else
|
76
|
+
obj
|
77
|
+
end
|
78
|
+
when Array
|
79
|
+
obj.map { |o| convert_object(o) }
|
80
|
+
when Hash
|
81
|
+
HashStruct.new(obj)
|
82
|
+
when HashStruct
|
83
|
+
obj
|
84
|
+
else
|
85
|
+
obj
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hashstruct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Labovitz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-13 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! "\n HashStruct provides an object based on Hash, but acts like Struct
|
15
|
+
(or OpenStruct), providing helpful\n accessors for each key from the get-go.
|
16
|
+
It also magically parses string values when it can (eg, dates,\n URIs, numbers,
|
17
|
+
and does so recursively.\n "
|
18
|
+
email: johnl@johnlabovitz.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/hashstruct.rb
|
24
|
+
- README.mdown
|
25
|
+
homepage: http://github.com/jslabovitz/hashstruct
|
26
|
+
licenses: []
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 1.8.25
|
46
|
+
signing_key:
|
47
|
+
specification_version: 3
|
48
|
+
summary: Overly helpful magic hash structure.
|
49
|
+
test_files: []
|