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 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