structure 1.2.1 → 2.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/structure.rb +108 -41
- data/lib/structure/version.rb +1 -1
- metadata +49 -9
- data/lib/structure/class_methods.rb +0 -75
- data/lib/structure/double.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: deb97f3f6e161a8adad686e3245878eddfada43c12be7cce3b567c8a53e5616a
|
4
|
+
data.tar.gz: 7eaac7c7ff94778b2df81ebff8473a52cc17582d885713c031fe04ecf8cf3053
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a859a498b3c11a6687b190de2985a176a1aaf9a803ce45dca5e016a11731f315dfacac1054521671409cf44206228d81582214316b1135e17c819c8ed36f5af1
|
7
|
+
data.tar.gz: d13ea6ab654295856d7086eaccfbf109b2bd6734761484eb8b2f3049cb17b4a1697e8afddc25eb2ef317118581c746b4203c05c74d947b405f4d53e4d68c6c1f
|
data/lib/structure.rb
CHANGED
@@ -1,70 +1,137 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
# A tiny library for lazy parsing data with memoized attributes
|
5
4
|
module Structure
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
value.inspect
|
5
|
+
class << self
|
6
|
+
def serialize(value)
|
7
|
+
if value.respond_to?(:attributes)
|
8
|
+
value.attributes
|
9
|
+
elsif value.is_a?(::Array)
|
10
|
+
value.map { |element| serialize(element) }
|
11
|
+
else
|
12
|
+
value
|
13
|
+
end
|
16
14
|
end
|
17
|
-
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
value.map { |subvalue| serialize(subvalue) }
|
24
|
-
else
|
25
|
-
value
|
16
|
+
private
|
17
|
+
|
18
|
+
def included(base)
|
19
|
+
base.extend ClassMethods
|
26
20
|
end
|
27
21
|
end
|
28
22
|
|
29
|
-
def
|
30
|
-
|
23
|
+
def attribute_names
|
24
|
+
self.class.attribute_names
|
31
25
|
end
|
32
26
|
|
33
|
-
# Returns a hash of all the attributes with their names as keys and the
|
34
|
-
# values of the attributes as values
|
35
27
|
def attributes
|
36
28
|
attribute_names.each_with_object({}) do |key, hash|
|
37
|
-
hash[key] = Structure.serialize(send(key))
|
29
|
+
hash[key] = ::Structure.serialize(send(key))
|
38
30
|
end
|
39
31
|
end
|
40
32
|
|
41
|
-
|
42
|
-
|
43
|
-
self.class.attribute_names
|
33
|
+
def to_h
|
34
|
+
attributes
|
44
35
|
end
|
45
36
|
|
46
|
-
def
|
47
|
-
|
37
|
+
def to_s
|
38
|
+
data = attribute_names.map { |key| "#{key}=#{send(key)}" }.join(', ')
|
39
|
+
"#<#{[self.class.name, data].compact.join(' ')}>"
|
40
|
+
end
|
48
41
|
|
42
|
+
def inspect
|
43
|
+
to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(other)
|
49
47
|
attributes == other.attributes
|
50
48
|
end
|
51
49
|
|
52
|
-
def
|
53
|
-
|
54
|
-
values = attribute_names
|
55
|
-
.map { |key| "#{key}=#{Structure.inspect(send(key))}" }
|
56
|
-
.join(', ')
|
50
|
+
def eql?(other)
|
51
|
+
return false if other.class != self.class
|
57
52
|
|
58
|
-
|
53
|
+
self == other
|
59
54
|
end
|
60
55
|
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
def freeze
|
57
|
+
attribute_names.each { |key| send(key) }
|
58
|
+
super
|
59
|
+
end
|
64
60
|
|
65
61
|
private
|
66
62
|
|
67
|
-
def
|
68
|
-
@
|
63
|
+
def with_mutex(&block)
|
64
|
+
@mutex.owned? ? block.call : @mutex.synchronize { block.call }
|
65
|
+
end
|
66
|
+
|
67
|
+
# The class interface
|
68
|
+
module ClassMethods
|
69
|
+
attr_reader :attribute_names
|
70
|
+
|
71
|
+
class << self
|
72
|
+
def extended(base)
|
73
|
+
base.instance_variable_set :@attribute_names, []
|
74
|
+
base.send :override_initialize
|
75
|
+
end
|
76
|
+
|
77
|
+
private :extended
|
78
|
+
end
|
79
|
+
|
80
|
+
def attribute(name, &block)
|
81
|
+
name = name.to_s
|
82
|
+
|
83
|
+
if name.end_with?('?')
|
84
|
+
name = name.chop
|
85
|
+
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
86
|
+
def #{name}?
|
87
|
+
#{name}
|
88
|
+
end
|
89
|
+
CODE
|
90
|
+
end
|
91
|
+
|
92
|
+
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
93
|
+
def #{name}
|
94
|
+
with_mutex do
|
95
|
+
break if defined?(@#{name})
|
96
|
+
|
97
|
+
@#{name} = unmemoized_#{name}
|
98
|
+
end
|
99
|
+
|
100
|
+
@#{name}
|
101
|
+
end
|
102
|
+
CODE
|
103
|
+
private define_method "unmemoized_#{name}", block
|
104
|
+
@attribute_names << name
|
105
|
+
|
106
|
+
name.to_sym
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def override_initialize
|
112
|
+
class_eval do
|
113
|
+
unless method_defined?(:overriding_initialize)
|
114
|
+
define_method :overriding_initialize do |*arguments, &block|
|
115
|
+
@mutex = ::Thread::Mutex.new
|
116
|
+
original_initialize(*arguments, &block)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
return if instance_method(:initialize) ==
|
121
|
+
instance_method(:overriding_initialize)
|
122
|
+
|
123
|
+
alias_method :original_initialize, :initialize
|
124
|
+
alias_method :initialize, :overriding_initialize
|
125
|
+
private :overriding_initialize, :original_initialize
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def method_added(name)
|
130
|
+
override_initialize if name == :initialize
|
131
|
+
end
|
132
|
+
|
133
|
+
def inherited(subclass)
|
134
|
+
subclass.instance_variable_set :@attribute_names, attribute_names.dup
|
135
|
+
end
|
69
136
|
end
|
70
137
|
end
|
data/lib/structure/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: structure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hakan Ensari
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
12
|
-
dependencies:
|
11
|
+
date: 2019-08-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
13
55
|
description:
|
14
56
|
email:
|
15
57
|
executables: []
|
@@ -17,8 +59,6 @@ extensions: []
|
|
17
59
|
extra_rdoc_files: []
|
18
60
|
files:
|
19
61
|
- lib/structure.rb
|
20
|
-
- lib/structure/class_methods.rb
|
21
|
-
- lib/structure/double.rb
|
22
62
|
- lib/structure/version.rb
|
23
63
|
homepage:
|
24
64
|
licenses:
|
@@ -32,15 +72,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
32
72
|
requirements:
|
33
73
|
- - ">="
|
34
74
|
- !ruby/object:Gem::Version
|
35
|
-
version: '
|
75
|
+
version: '2.4'
|
36
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
77
|
requirements:
|
38
|
-
- - "
|
78
|
+
- - ">"
|
39
79
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
80
|
+
version: 1.3.1
|
41
81
|
requirements: []
|
42
82
|
rubygems_version: 3.0.3
|
43
83
|
signing_key:
|
44
84
|
specification_version: 4
|
45
|
-
summary:
|
85
|
+
summary: Lazy parse data into memoized attributes
|
46
86
|
test_files: []
|
@@ -1,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Structure
|
4
|
-
module ClassMethods
|
5
|
-
# Returns an array of attribute names as strings
|
6
|
-
attr_reader :attribute_names
|
7
|
-
|
8
|
-
def self.extended(base)
|
9
|
-
base.instance_variable_set :@attribute_names, []
|
10
|
-
base.send :__overwrite_initialize
|
11
|
-
end
|
12
|
-
|
13
|
-
def attribute(name, &block)
|
14
|
-
name = name.to_s
|
15
|
-
|
16
|
-
if name.end_with?('?')
|
17
|
-
name = name.chop
|
18
|
-
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
19
|
-
def #{name}?
|
20
|
-
#{name}
|
21
|
-
end
|
22
|
-
CODE
|
23
|
-
end
|
24
|
-
|
25
|
-
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
26
|
-
def #{name}
|
27
|
-
__exclusive {
|
28
|
-
break if @__table.key?("#{name}")
|
29
|
-
|
30
|
-
@__table["#{name}"] = __get_#{name}
|
31
|
-
@__table["#{name}"].freeze
|
32
|
-
}
|
33
|
-
|
34
|
-
@__table["#{name}"]
|
35
|
-
end
|
36
|
-
CODE
|
37
|
-
|
38
|
-
private define_method "__get_#{name}", block
|
39
|
-
|
40
|
-
@attribute_names << name
|
41
|
-
|
42
|
-
name.to_sym
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def __overwrite_initialize
|
48
|
-
class_eval do
|
49
|
-
unless method_defined?(:__custom_initialize)
|
50
|
-
define_method :__custom_initialize do |*arguments, &block|
|
51
|
-
@__mutex = ::Thread::Mutex.new
|
52
|
-
@__table = {}
|
53
|
-
__original_initialize(*arguments, &block)
|
54
|
-
freeze
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
return if instance_method(:initialize) ==
|
59
|
-
instance_method(:__custom_initialize)
|
60
|
-
|
61
|
-
alias_method :__original_initialize, :initialize
|
62
|
-
alias_method :initialize, :__custom_initialize
|
63
|
-
private :__custom_initialize, :__original_initialize
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def method_added(name)
|
68
|
-
__overwrite_initialize if name == :initialize
|
69
|
-
end
|
70
|
-
|
71
|
-
def inherited(subclass)
|
72
|
-
subclass.instance_variable_set :@attribute_names, @attribute_names.dup
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
data/lib/structure/double.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Structure
|
4
|
-
module ClassMethods
|
5
|
-
# Creates a double that mocks a value object built with Structure during a
|
6
|
-
# test
|
7
|
-
#
|
8
|
-
# The double has an alternative constructor that takes a hash to set values.
|
9
|
-
# Otherwise, it shares the public API of the mocked value object.
|
10
|
-
def double
|
11
|
-
klass = Class.new(self)
|
12
|
-
|
13
|
-
(private_instance_methods(false) + protected_instance_methods(false) -
|
14
|
-
[:initialize]).each do |name|
|
15
|
-
klass.send :undef_method, name
|
16
|
-
end
|
17
|
-
|
18
|
-
klass.module_eval do
|
19
|
-
def initialize(values = {})
|
20
|
-
values.each do |key, value|
|
21
|
-
instance_variable_set :"@#{key}", value
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
attribute_names.each do |name|
|
26
|
-
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
27
|
-
private def __get_#{name}
|
28
|
-
@#{name}
|
29
|
-
end
|
30
|
-
CODE
|
31
|
-
end
|
32
|
-
|
33
|
-
module_eval(&Proc.new) if block_given?
|
34
|
-
end
|
35
|
-
|
36
|
-
class << klass
|
37
|
-
undef_method :double
|
38
|
-
end
|
39
|
-
|
40
|
-
klass
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|