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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6b0dd37534ddbab651d055ac20449409d4d2a26f943b5ece647eafe56d0be1a
4
- data.tar.gz: 9b41302fd50f1d031a55f46fb656e1c2985f3a6ca39b48997992de2a9355ad44
3
+ metadata.gz: deb97f3f6e161a8adad686e3245878eddfada43c12be7cce3b567c8a53e5616a
4
+ data.tar.gz: 7eaac7c7ff94778b2df81ebff8473a52cc17582d885713c031fe04ecf8cf3053
5
5
  SHA512:
6
- metadata.gz: 1a85161835d1cc3e87ae05dcb5d2ada4647a360a4df5260f6adc5679db9e1d1b397924e6c6e2933aed87a27dc154d5049178abbbb8e0de1393b6965fa8b8ed02
7
- data.tar.gz: 20e3a9416b98321020959cc8f3522d6c07843a78df69428a87291d1f60eb1d2aab2ac9d8bf51ecd0878b1ba69d1aea72465f6cec0126644b3779633a10d2b5d3
6
+ metadata.gz: a859a498b3c11a6687b190de2985a176a1aaf9a803ce45dca5e016a11731f315dfacac1054521671409cf44206228d81582214316b1135e17c819c8ed36f5af1
7
+ data.tar.gz: d13ea6ab654295856d7086eaccfbf109b2bd6734761484eb8b2f3049cb17b4a1697e8afddc25eb2ef317118581c746b4203c05c74d947b405f4d53e4d68c6c1f
@@ -1,70 +1,137 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'structure/class_methods'
4
-
3
+ # A tiny library for lazy parsing data with memoized attributes
5
4
  module Structure
6
- def self.inspect(value)
7
- if value.is_a?(::Array)
8
- inspection = value.take(3)
9
- .map { |subvalue| inspect(subvalue) }
10
- .join(', ')
11
- inspection += '...' if value.size > 3
12
-
13
- "[#{inspection}]"
14
- else
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
- def self.serialize(value)
20
- if value.respond_to?(:attributes)
21
- value.attributes
22
- elsif value.is_a?(::Array)
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 self.included(base)
30
- base.extend ClassMethods
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
- # Returns an array of attribute names as strings
42
- def attribute_names
43
- self.class.attribute_names
33
+ def to_h
34
+ attributes
44
35
  end
45
36
 
46
- def ==(other)
47
- return false unless other.respond_to?(:attributes)
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 inspect
53
- name = self.class.name || self.class.to_s.gsub(/[^\w:]/, '')
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
- "#<#{name} #{values}>"
53
+ self == other
59
54
  end
60
55
 
61
- alias to_h attributes
62
- alias eql? ==
63
- alias to_s inspect
56
+ def freeze
57
+ attribute_names.each { |key| send(key) }
58
+ super
59
+ end
64
60
 
65
61
  private
66
62
 
67
- def __exclusive(&block)
68
- @__mutex.owned? ? block.call : @__mutex.synchronize { block.call }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Structure
4
- VERSION = '1.2.1'
4
+ VERSION = '2.0.0.beta'
5
5
  end
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: 1.2.1
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-05-26 00:00:00.000000000 Z
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: '0'
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: '0'
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: Parse data into value objects
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
@@ -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