mimi-struct 0.1.0 → 1.0.0

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
  SHA1:
3
- metadata.gz: 4ce18d3926ef7a9a05740b35362bd3c8d285f6ea
4
- data.tar.gz: 0b668e2e2e2424ccdc1b792aa6c83748a5e6ab54
3
+ metadata.gz: 8064ab3ebc35af445e5be33a322db6d14a31693e
4
+ data.tar.gz: f8d1a850531925e12fe0c473647dc519538072f0
5
5
  SHA512:
6
- metadata.gz: '0478d07e8a60c92362638ae261410d4cb96889958b192920d935ce0a5fa2cbdfd7907c27f0ae495273223bc143bb1850aa8490e3960dbd3f4864bb1baa70ba44'
7
- data.tar.gz: 1523ca2197640b826f7b7a524ccd45763bc857c7e53d32620686de912bcc0bc3ebd711166fe5e7c5c33d5919a61a2d8b7ede0b64b73693b5327e18ff72053927
6
+ metadata.gz: 3d62b706cf2bffafb74bd09ead748382b95e1a4d297c6976832968065f5ecc7c9a6ca65b9daa7baed14f741c46719891ceaa23fcd7fdc921b8a73b0344e90fea
7
+ data.tar.gz: ad312292e8c75438467baa6754658f26e101040dd9ee1121dc6a4ddf349975c09d72f5ebe72e91566ddc384a33a8e3bd6fe835d982373de8dce817ddc9a8c506
data/.gitignore CHANGED
@@ -1,11 +1,10 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
+ /Gemfile.lock
3
4
  /_yardoc/
4
5
  /coverage/
5
6
  /doc/
6
7
  /pkg/
7
8
  /spec/reports/
8
9
  /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
10
+ /.rspec_status
data/bin/console CHANGED
@@ -6,9 +6,5 @@ require "mimi/struct"
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
9
+ require "pry"
10
+ Pry.start
@@ -0,0 +1,29 @@
1
+ require "mimi/struct"
2
+ require "json"
3
+
4
+ class User < Mimi::Struct
5
+ attribute :id
6
+ attribute :name, from: :username
7
+ end
8
+
9
+ class Comment < Mimi::Struct
10
+ attribute :author, from: :user, using: User
11
+ attribute :text
12
+ end
13
+
14
+ class Post < Mimi::Struct
15
+ attribute :id
16
+ attribute :author, using: User
17
+ attribute :text
18
+ attribute :comments, using: Comment
19
+ end
20
+
21
+ user1 = { id: 1, username: "Alice", email: "alice@gmail.com" }
22
+ user2 = { id: 2, username: "Bob", email: "bob@gmail.com" }
23
+ comm1 = { user: user1, text: "Mmm?" }
24
+ comm2 = { user: user2, text: "Hi!" }
25
+ post_params = { id: 1, author: user1, text: "Hello, world!", comments: [comm1, comm2] }
26
+
27
+ # Maps Post including all nested data
28
+ post = Post.new(post_params)
29
+ puts JSON.pretty_generate post.to_h
data/examples/poro.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "mimi/struct"
2
+
3
+ #
4
+ # Mapping a PORO
5
+ #
6
+
7
+ class User < Mimi::Struct
8
+ attribute :id
9
+ attribute :name, from: :username
10
+ end
11
+
12
+ class UserData
13
+ attr_reader :id, :username
14
+
15
+ def initialize(username)
16
+ @id = rand(1000)
17
+ @username = username
18
+ end
19
+ end
20
+
21
+ user_data = UserData.new("John")
22
+
23
+ puts User.new(user_data).to_h
@@ -0,0 +1,13 @@
1
+ require "mimi/struct"
2
+
3
+ # Simple data mapping
4
+ #
5
+ class User < Mimi::Struct
6
+ attribute :id
7
+ attribute :name, from: :username
8
+ end
9
+
10
+ # Maps defined attributes, filters out all the extra attributes:
11
+ user = User.new(id: 1, username: "John", email: "john@gmail.com")
12
+
13
+ puts user.to_h
data/lib/mimi/struct.rb CHANGED
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mimi/core"
4
+
3
5
  module Mimi
4
6
  #
5
- # A Struct that can be initialized from a Hash or another Struct.
7
+ # A Struct that can be initialized from a Hash or a PORO.
6
8
  #
7
- # A Struct declares its attributes and rules, which define how its attrubutes
9
+ # A Struct declares its attributes and rules, which define how its attributes
8
10
  # are mapped from input data.
9
11
  #
10
- class Struct < ::Struct
11
-
12
+ class Struct < Mimi::Core::Struct
13
+ #
12
14
  # Default attribute mapper
13
15
  #
14
16
  # Maps value of the source attribute to the target attribute.
@@ -16,9 +18,9 @@ module Mimi
16
18
  #
17
19
  DEFAULT_ATTRIBUTE_MAPPER = -> (o, params) do
18
20
  if params.key?(:default)
19
- o.to_h.key?(params[:from]) || call_as_proc(params[:default], o, params)
21
+ o.respond_to?(params[:from]) || call_as_proc(params[:default], o, params)
20
22
  else
21
- o[params[:from]]
23
+ o.send(params[:from])
22
24
  end
23
25
  end
24
26
 
@@ -27,7 +29,27 @@ module Mimi
27
29
  # Skips the attribute if the source attribute is not set.
28
30
  #
29
31
  DEFAULT_IF_FOR_OPTIONAL = -> (o, params) do
30
- o.to_h.key?(params[:from])
32
+ o.respond_to?(params[:from])
33
+ end
34
+
35
+ # Creates a mapped Struct object from another object
36
+ #
37
+ # @param source [Hash,Object]
38
+ #
39
+ def initialize(source)
40
+ source = Mimi::Core::Struct.new(source) if source.is_a?(Hash)
41
+ attributes = self.class.transform_attributes(source)
42
+ super(attributes)
43
+ rescue StandardError => e
44
+ raise e.class, "Failed to construct #{self.class}: #{e}", e.backtrace
45
+ end
46
+
47
+ # Fetches an attribute with given name
48
+ #
49
+ # @param name [Symbol]
50
+ #
51
+ def [](name)
52
+ @attributes[name.to_sym]
31
53
  end
32
54
 
33
55
  # Presents this Struct as a Hash, deeply converting nested Structs
@@ -35,7 +57,7 @@ module Mimi
35
57
  # @return [Hash]
36
58
  #
37
59
  def to_h
38
- super.map do |k, v|
60
+ attributes.map do |k, v|
39
61
  [k, self.class.value_to_h(v)]
40
62
  end.to_h
41
63
  end
@@ -45,7 +67,7 @@ module Mimi
45
67
  # @return [Hash]
46
68
  #
47
69
  def attributes
48
- to_h
70
+ @attributes
49
71
  end
50
72
 
51
73
  # An attribute definition
@@ -109,7 +131,7 @@ module Mimi
109
131
  if obj_or_collection.is_a?(Array)
110
132
  obj_or_collection.map { |o| self << o }
111
133
  else
112
- transform(obj_or_collection)
134
+ new(obj_or_collection)
113
135
  end
114
136
  end
115
137
 
@@ -141,36 +163,19 @@ module Mimi
141
163
  @group_params ||= [{}]
142
164
  end
143
165
 
144
- # Creates a Struct instance from given parameters
145
- #
146
- # @param source [Struct,Hash]
147
- #
148
- private_class_method def self.transform(source)
149
- if source.is_a?(Struct)
150
- # do nothing
151
- elsif source.is_a?(Hash)
152
- source = Struct.new(*source.to_h.keys).new(*source.to_h.values)
153
- else
154
- raise ArgumentError, "Struct or Hash is expected as source"
155
- end
156
- attributes = transform_attributes(source)
157
- new(*attributes.keys).new(*attributes.values)
158
- rescue StandardError => e
159
- raise "Failed to construct #{self}: #{e}"
160
- end
161
-
162
166
  # Transform attributes according to rules
163
167
  #
164
168
  # @param source [Struct]
165
169
  # @return [Hash] map of attribute name -> value
166
170
  #
167
- private_class_method def self.transform_attributes(source)
168
- attribute_definitions.map do |k, params|
171
+ def self.transform_attributes(source)
172
+ result = attribute_definitions.map do |k, params|
169
173
  if params[:if].is_a?(Proc)
170
174
  next unless call_as_proc(params[:if], source, params)
171
175
  end
172
176
  [k, transform_single_attribute(source, k, params)]
173
177
  end.compact.to_h
178
+ result
174
179
  end
175
180
 
176
181
  # Transforms a single attribute value according to rules passed as params
@@ -183,7 +188,7 @@ module Mimi
183
188
  private_class_method def self.transform_single_attribute(source, key, params)
184
189
  return call_as_proc(params[:using], source, params) if params[:using].is_a?(Proc)
185
190
  if params[:using].is_a?(Class) && params[:using] < Mimi::Struct
186
- return params[:using] << source[params[:from]]
191
+ return params[:using] << source.send(params[:from])
187
192
  end
188
193
  raise "unexpected :using type: #{params[:using].class}"
189
194
  rescue StandardError => e
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mimi/struct"
4
-
5
3
  module Mimi
6
4
  class Struct
7
- VERSION = "0.1.0"
5
+ VERSION = "1.0.0"
8
6
  end
9
7
  end
data/mimi-struct.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  lib = File.expand_path("lib", __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "mimi/struct/version"
3
+ require "mimi/struct"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "mimi-struct"
@@ -30,9 +30,10 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ["lib"]
32
32
 
33
- spec.add_dependency "mimi-core", "~> 1.0"
33
+ spec.add_dependency "mimi-core", "~> 1.1"
34
34
 
35
35
  spec.add_development_dependency "bundler", "~> 2.0"
36
+ spec.add_development_dependency "pry", "~> 0.12"
36
37
  spec.add_development_dependency "rake", "~> 10.0"
37
38
  spec.add_development_dependency "rspec", "~> 3.0"
38
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mimi-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-23 00:00:00.000000000 Z
11
+ date: 2019-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mimi-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.12'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -78,13 +92,15 @@ files:
78
92
  - ".travis.yml"
79
93
  - CODE_OF_CONDUCT.md
80
94
  - Gemfile
81
- - Gemfile.lock
82
95
  - LICENSE.txt
83
96
  - README.md
84
97
  - Rakefile
85
98
  - bin/console
86
99
  - bin/setup
87
100
  - examples/customer.rb
101
+ - examples/nested.rb
102
+ - examples/poro.rb
103
+ - examples/simple.rb
88
104
  - lib/mimi/struct.rb
89
105
  - lib/mimi/struct/version.rb
90
106
  - mimi-struct.gemspec
data/Gemfile.lock DELETED
@@ -1,39 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- mimi-struct (0.1.0)
5
- mimi-core (~> 1.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- diff-lcs (1.3)
11
- hashie (3.6.0)
12
- mimi-core (1.0.0)
13
- hashie (~> 3.6)
14
- rake (10.5.0)
15
- rspec (3.8.0)
16
- rspec-core (~> 3.8.0)
17
- rspec-expectations (~> 3.8.0)
18
- rspec-mocks (~> 3.8.0)
19
- rspec-core (3.8.1)
20
- rspec-support (~> 3.8.0)
21
- rspec-expectations (3.8.4)
22
- diff-lcs (>= 1.2.0, < 2.0)
23
- rspec-support (~> 3.8.0)
24
- rspec-mocks (3.8.1)
25
- diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.8.0)
27
- rspec-support (3.8.2)
28
-
29
- PLATFORMS
30
- ruby
31
-
32
- DEPENDENCIES
33
- bundler (~> 2.0)
34
- mimi-struct!
35
- rake (~> 10.0)
36
- rspec (~> 3.0)
37
-
38
- BUNDLED WITH
39
- 2.0.2