structure 1.2.1 → 2.0.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|