better_struct 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -18
- data/better_struct.gemspec +0 -2
- data/lib/better_struct.rb +11 -22
- data/lib/better_struct/methodize.rb +46 -0
- data/lib/better_struct/version.rb +1 -1
- metadata +3 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63739e5a654591d3d685a383a163fca50902f3b2
|
4
|
+
data.tar.gz: 8ac3510abea38370cbe2d67a951deec7d1c002bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45b9c991c3010cfd5ce2b25a853bbffd2f0bef51b6479770571141b8b293b01ceef9ab93102d6054e14a91aae4715b1172768afd37791d0a0d4130d457dc9b76
|
7
|
+
data.tar.gz: 03f58914d44f74f1d4a2eafb045066b338723f13e603fa32af51f9555aec93ecc1097d1c4aab056d3c7f1803a75807ebc1fef0d3651a10f2fb49661bbb9d0363
|
data/README.md
CHANGED
@@ -10,12 +10,12 @@ It behaves like an OpenStruct on steroids with monad.
|
|
10
10
|
hash = { "FooBar1" => { foo_bar2: "Hello World!" } }
|
11
11
|
|
12
12
|
# Instead of this:
|
13
|
-
if hash["FooBar1"] && hash["FooBar1"][:foo_bar2]
|
14
|
-
|
13
|
+
if hash["FooBar1"] && hash["FooBar1"][:foo_bar2] && hash["FooBar1"][:foo_bar2].respond_to?(:sub)
|
14
|
+
hash["FooBar1"][:foo_bar2].sub("Hello ", "") # => "World!"
|
15
15
|
end
|
16
16
|
|
17
17
|
# Simply use:
|
18
|
-
|
18
|
+
BetterStruct.new(hash).foo_bar1.foo_bar2.sub("Hello ", "").value # => "World!"
|
19
19
|
```
|
20
20
|
|
21
21
|
## Installation
|
@@ -39,7 +39,7 @@ Or install it yourself as:
|
|
39
39
|
#### Maybe monad
|
40
40
|
|
41
41
|
```ruby
|
42
|
-
BetterStruct.new(nil) == BetterStruct.new(nil).
|
42
|
+
BetterStruct.new(nil) == BetterStruct.new(nil).this_method.does_not_exist # => true
|
43
43
|
```
|
44
44
|
|
45
45
|
#### Everything is wrapped
|
@@ -47,21 +47,16 @@ BetterStruct.new(nil) == BetterStruct.new(nil).some_method # => true
|
|
47
47
|
```ruby
|
48
48
|
better_struct = BetterStruct.new("foobar")
|
49
49
|
|
50
|
-
better_struct[0..2].is_a?(BetterStruct) # => true
|
51
50
|
better_struct[0..2] == BetterStruct.new("foo") # => true
|
52
51
|
```
|
53
52
|
|
54
53
|
```ruby
|
55
54
|
better_struct = BetterStruct.new([1, 2, 3])
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
result.is_a?(BetterStruct) # => true
|
60
|
-
result == BetterStruct.new(true) # => true
|
61
|
-
|
56
|
+
better_struct.all? { |i| i.is_a?(BetterStruct) } == BetterStruct.new(true) # => true
|
62
57
|
```
|
63
58
|
|
64
|
-
#### Like OpenStruct
|
59
|
+
#### Like an OpenStruct on steroids
|
65
60
|
|
66
61
|
```ruby
|
67
62
|
some_hash = { "FooBar1" => { foo_bar2: "Hello World!" } }
|
@@ -85,21 +80,21 @@ better_struct.gsub("foo", "super-").value == "super-foo" # => true
|
|
85
80
|
|
86
81
|
## Benchmarking
|
87
82
|
|
88
|
-
|
83
|
+
**BetterStruct** is even faster than an OpenStruct:
|
89
84
|
|
90
85
|
```
|
91
86
|
$ ruby scripts/benchmark.rb
|
92
87
|
|
93
88
|
Calculating -------------------------------------
|
94
|
-
OpenStruct
|
95
|
-
BetterStruct 7.
|
89
|
+
OpenStruct 7.334k i/100ms
|
90
|
+
BetterStruct 7.856k i/100ms
|
96
91
|
-------------------------------------------------
|
97
|
-
OpenStruct 75.
|
98
|
-
BetterStruct
|
92
|
+
OpenStruct 75.971k (± 7.1%) i/s - 381.368k
|
93
|
+
BetterStruct 84.520k (± 4.5%) i/s - 424.224k
|
99
94
|
|
100
95
|
Comparison:
|
101
|
-
BetterStruct:
|
102
|
-
OpenStruct:
|
96
|
+
BetterStruct: 84519.8 i/s
|
97
|
+
OpenStruct: 75971.1 i/s - 1.11x slower
|
103
98
|
```
|
104
99
|
|
105
100
|
## Contributing
|
data/better_struct.gemspec
CHANGED
@@ -18,8 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "activesupport", ">= 3.2.0"
|
22
|
-
|
23
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
24
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
23
|
spec.add_development_dependency "minitest", "~> 5.5"
|
data/lib/better_struct.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require "
|
2
|
-
|
1
|
+
require "set"
|
2
|
+
require_relative "./better_struct/version"
|
3
|
+
require_relative "./better_struct/methodize"
|
3
4
|
|
4
5
|
class BetterStruct
|
5
|
-
PARAMETERIZE_SEPARATOR = "_".freeze
|
6
6
|
EQUAL_SIGN = "=".freeze
|
7
7
|
MAP_METHOD_NAMES = %i(map map!).to_set.freeze
|
8
8
|
|
@@ -26,21 +26,11 @@ class BetterStruct
|
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
def methodize(string)
|
30
|
-
result = ActiveSupport::Inflector.underscore(string)
|
31
|
-
|
32
|
-
if result =~ /[^\w]/
|
33
|
-
ActiveSupport::Inflector.parameterize(result, PARAMETERIZE_SEPARATOR)
|
34
|
-
else
|
35
|
-
result
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
29
|
def wrap(value)
|
40
30
|
value.is_a?(self.class) ? self : self.class.new(value)
|
41
31
|
end
|
42
32
|
|
43
|
-
def wrap_block_args(
|
33
|
+
def wrap_block_args(&block)
|
44
34
|
return if block.nil?
|
45
35
|
|
46
36
|
Proc.new do |*args|
|
@@ -52,16 +42,15 @@ private
|
|
52
42
|
def method_missing(method_name, *args, &block)
|
53
43
|
if value.respond_to?(method_name)
|
54
44
|
delegate_method(method_name, *args, &block)
|
55
|
-
elsif assignment?(method_name
|
56
|
-
|
57
|
-
@defined_methods[attribute] = args.first
|
45
|
+
elsif assignment?(method_name) && defined_methods
|
46
|
+
@defined_methods[methodize(method_name[0...-1])] = args.first
|
58
47
|
else
|
59
48
|
wrap(defined_methods[method_name.to_s])
|
60
49
|
end
|
61
50
|
end
|
62
51
|
|
63
|
-
def assignment?(method_name
|
64
|
-
method_name[-1] == EQUAL_SIGN
|
52
|
+
def assignment?(method_name)
|
53
|
+
method_name[-1] == EQUAL_SIGN
|
65
54
|
end
|
66
55
|
|
67
56
|
def defined_methods
|
@@ -77,12 +66,12 @@ private
|
|
77
66
|
end
|
78
67
|
|
79
68
|
def delegate_method(method_name, *args, &block)
|
80
|
-
result =
|
69
|
+
result = value.public_send(method_name, *unwrap_items(args), &wrap_block_args(&block))
|
81
70
|
|
82
71
|
if MAP_METHOD_NAMES.include?(method_name)
|
83
|
-
wrap(unwrap_items(result
|
72
|
+
wrap(unwrap_items(result))
|
84
73
|
else
|
85
|
-
result
|
74
|
+
wrap(result)
|
86
75
|
end
|
87
76
|
end
|
88
77
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class BetterStruct
|
2
|
+
EMPTY_STRING = "".freeze
|
3
|
+
UNDERSCORE_SIGN = "_".freeze
|
4
|
+
|
5
|
+
TRANSLITERATION_FROM = "ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž".freeze
|
6
|
+
TRANSLITERATION_TO = "AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz".freeze
|
7
|
+
|
8
|
+
UPCASE_REGEXP = /[A-Z]/.freeze
|
9
|
+
NOT_UNDERSCORED_REGEXP = /[^a-z0-9_]/.freeze
|
10
|
+
NON_ENGLISH_REGEXP = /[#{ TRANSLITERATION_FROM }]/.freeze
|
11
|
+
UNDERSCORE_DUPLICATES_REGEXP = /#{ UNDERSCORE_SIGN }{2,}/.freeze
|
12
|
+
UNDERSCORE_BEGIN_OR_END_REGEXP = /^#{ UNDERSCORE_SIGN }|#{ UNDERSCORE_SIGN }$/.freeze
|
13
|
+
CAMELCASE_ABBREVIATION_REGEX = /([A-Z\d]+)([A-Z][a-z])/.freeze
|
14
|
+
CAMELCASE_REGEX = /([a-z\d])([A-Z])/.freeze
|
15
|
+
|
16
|
+
UNDERSCORE_MASK = '\1_\2'.freeze
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def methodize(string)
|
21
|
+
return string unless string =~ NOT_UNDERSCORED_REGEXP
|
22
|
+
|
23
|
+
string = string.dup
|
24
|
+
|
25
|
+
transliterate!(string)
|
26
|
+
underscore!(string)
|
27
|
+
string
|
28
|
+
end
|
29
|
+
|
30
|
+
def transliterate!(string)
|
31
|
+
if string =~ NON_ENGLISH_REGEXP
|
32
|
+
string.tr!(TRANSLITERATION_FROM, TRANSLITERATION_TO)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def underscore!(string)
|
37
|
+
if string =~ NOT_UNDERSCORED_REGEXP
|
38
|
+
string.gsub!(CAMELCASE_ABBREVIATION_REGEX, UNDERSCORE_MASK)
|
39
|
+
string.gsub!(CAMELCASE_REGEX, UNDERSCORE_MASK)
|
40
|
+
string.downcase!
|
41
|
+
string.gsub!(NOT_UNDERSCORED_REGEXP, UNDERSCORE_SIGN)
|
42
|
+
string.gsub!(UNDERSCORE_DUPLICATES_REGEXP, UNDERSCORE_SIGN)
|
43
|
+
string.gsub!(UNDERSCORE_BEGIN_OR_END_REGEXP, EMPTY_STRING)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: better_struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evgeny Li
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ! '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 3.2.0
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ! '>='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 3.2.0
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +108,7 @@ files:
|
|
122
108
|
- Rakefile
|
123
109
|
- better_struct.gemspec
|
124
110
|
- lib/better_struct.rb
|
111
|
+
- lib/better_struct/methodize.rb
|
125
112
|
- lib/better_struct/version.rb
|
126
113
|
- test/better_struct_test.rb
|
127
114
|
homepage: https://github.com/exAspArk/better_struct
|