client-data-adapter 0.0.1 → 0.1.0.pre.beta.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
  SHA256:
3
- metadata.gz: 9d22c20655882168eee2a1aebb0d9baa020eeb7fc5de989ab7792b0ba0d24714
4
- data.tar.gz: 047c8570cfff746117be247f0ae33f2c4730d0a4f5c46a66e2b656541ca3b7d4
3
+ metadata.gz: ae1af95313ca1dd4dfa4c1fa52e0ef35190f34b18ce6551d4c7a28966b7d5276
4
+ data.tar.gz: 69288c481e2581cc2f6620363810370d91620ec4de09197382567335030286ce
5
5
  SHA512:
6
- metadata.gz: c5dfc5fef8188b94dc8c044203848449af5a6428b5e2a7af9f06c212b7df6abbd27830c3244d15f97151906e3c1290d091a3f74b41300ac7e8d925bacee384e6
7
- data.tar.gz: 93eb2e996f82fdc2535d7e10e4df89f9e48271a88e15966dddac6956730c997bb11e320188c924648118ceb33b541c94238b84acbed0ef36615f6c5b2ebd8b4a
6
+ metadata.gz: 453755d6922cae9c97db0bd879c5152008ba5012a661ebc4f47d53860a6e2f36bbcc5ab0a2d03213501845e59ba1197f3336e17e2314e48821613ad46820b46d
7
+ data.tar.gz: 315ca608ef5326325fa0be42e17e78da389c6e97cd1b43427aeb02b93d0750efa13d31abb1dc2f4c2119eb993082ac1b5e2299cf88cef3220447a92a458c2d84
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore CHANGED
@@ -2,3 +2,7 @@
2
2
  .vscode
3
3
  .idea
4
4
  .DS_Store
5
+ coverage
6
+ .yardoc
7
+ Gemfile.lock
8
+ doc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ env:
3
+ - IS_CI=1
4
+ rvm:
5
+ - 2.1
6
+ - 2.5
7
+ - 2.6
8
+ script:
9
+ - bundle exec rspec
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://gems.ruby-china.com/'
2
+
3
+ group :development, :test do
4
+ gem 'rspec'
5
+ gem 'simplecov'
6
+ gem 'coveralls'
7
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019-present, By shadow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1 +1,361 @@
1
1
  # client-data-adapter
2
+
3
+ [![Build Status](https://travis-ci.org/jinghua000/client-data-adapter.svg?branch=master)](https://travis-ci.org/jinghua000/client-data-adapter)
4
+ [![Gem Version](https://badge.fury.io/rb/client-data-adapter.svg)](https://rubygems.org/gems/client-data-adapter)
5
+ [![Coverage Status](https://coveralls.io/repos/github/jinghua000/client-data-adapter/badge.svg?branch=master)](https://coveralls.io/github/jinghua000/client-data-adapter?branch=master)
6
+
7
+ ## Table of Contents
8
+ * [Introduction](#introduction)
9
+ * [Install](#install)
10
+ * [Usage](#usage)
11
+ + [`define_adapter`](#define_adapter)
12
+ + [`adapter`](#adapter)
13
+ + [`with`](#with)
14
+ - [Merge Methods](#merge-methods)
15
+ - [Pass Arguments](#pass-arguments)
16
+ - [Use Return](#use-return)
17
+ - [Read Methods Inside](#read-methods-inside)
18
+ + [`link_one`](#link_one)
19
+ + [`link_many`](#link_many)
20
+
21
+ ## Introduction
22
+
23
+ For unify data formats to transfer to clients.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ gem install client-data-adapter
29
+ ```
30
+
31
+ or in `Gemfile`
32
+
33
+ ```ruby
34
+ gem 'client-data-adapter'
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### `define_adapter`
40
+
41
+ Include library to model and use `define_adapter` to define the adapter.
42
+
43
+ ```ruby
44
+ # book.rb
45
+
46
+ include ClientDataAdapter
47
+
48
+ define_adapter do
49
+
50
+ # define your adapter here...
51
+
52
+ end
53
+
54
+ ```
55
+
56
+ ### `adapter`
57
+
58
+ `adapter` method define the main adapter, and common structure should be a `Hash`.
59
+
60
+ ```ruby
61
+ # ...
62
+
63
+ define_adapter do
64
+
65
+ adapter do
66
+ {
67
+ id: id,
68
+ title: title,
69
+ }
70
+ end
71
+
72
+ end
73
+ ```
74
+
75
+ In elsewhere
76
+
77
+ ```ruby
78
+ # ...
79
+
80
+ @book = Book.new(id: 1, title: 'My Book')
81
+ @book.adapter # => { id: 1, title: 'My Book' }
82
+
83
+ ```
84
+
85
+ ### `with`
86
+
87
+ And you are probably need some complex calculation or related some other class,
88
+ they maybe need some cost and don't need to load everywhere.
89
+
90
+ So we need use them *on-demand*.
91
+
92
+ ```ruby
93
+ # ...
94
+
95
+ define_adapter do
96
+
97
+ adapter do
98
+ {
99
+ id: id,
100
+ title: title,
101
+ }
102
+ end
103
+
104
+ with :my_complex_calc do
105
+ 'something complex'
106
+ end
107
+
108
+ end
109
+ ```
110
+
111
+ Then
112
+
113
+ ```ruby
114
+ # ...
115
+
116
+ @book = Book.new(id: 1, title: 'My Book')
117
+ @book.adapter(:my_complex_calc)
118
+ # => { id: 1, title: 'My Book', my_complex_calc: 'something complex' }
119
+ ```
120
+
121
+ #### Merge Methods
122
+
123
+ And you can merge any instance method of original class to the adapter result, such as
124
+
125
+ ```ruby
126
+ # book.rb
127
+
128
+ def full_title
129
+ "<#{title}>"
130
+ end
131
+ ```
132
+
133
+ Then you can use adapter like this
134
+
135
+ ```ruby
136
+ # ...
137
+
138
+ @book.adapter(:full_title)
139
+ # => { id: 1, title: 'My Book', full_title: '<My Book>' }
140
+ ```
141
+
142
+ It will set the `method name` as the `key`, and `returns` as the `value`.
143
+
144
+ > But notice that if method name is repeated, will trigger the one inside the adapter.
145
+
146
+ #### Pass Arguments
147
+
148
+ Sometimes we need pass some arguments to deal different case, you can write like this
149
+
150
+ ```ruby
151
+ @book.adapter(foo: [:bar, :baz])
152
+ ```
153
+
154
+ Arguments with `Hash` will consider the `key` as the `method name`,
155
+ and `values` as `arguments`.
156
+
157
+ To work with the method like this
158
+
159
+ ```ruby
160
+ def foo(*args)
161
+ args.join(',')
162
+ end
163
+ ```
164
+
165
+ or this
166
+
167
+ ```ruby
168
+ # ...
169
+
170
+ with :foo do |*args|
171
+ args.join(',')
172
+ end
173
+ ```
174
+
175
+ The result will be
176
+
177
+ ```ruby
178
+ @book.adapter(foo: [:bar, :baz])
179
+ # => { id: 1, title: 'My Book', foo: 'bar,baz' }
180
+ ```
181
+
182
+ #### Use Return
183
+
184
+ You can use return in adapter block to flow control.
185
+
186
+ ```ruby
187
+ # ...
188
+
189
+ with :id do
190
+ return 'i have no id' unless id
191
+ id
192
+ end
193
+ ```
194
+
195
+ It is works.
196
+
197
+ #### Read Methods Inside
198
+
199
+ If you define something inside the adapter, you can't read it directly.
200
+
201
+ ```ruby
202
+ # book.rb
203
+
204
+ define_adapter do
205
+ # ...
206
+
207
+ with :my_method do
208
+ 'invoke me please!'
209
+ end
210
+
211
+ end
212
+ ```
213
+
214
+ ```ruby
215
+ @book.my_method # => ERROR! No Method
216
+ ```
217
+
218
+ Since that adapter differentiate the namespace with the original class
219
+ to make naming more flexible.
220
+
221
+ It create a wrapper for the adapter named `AdapterWrapper`,
222
+ and exposed by the instance method `adapter_wrapper`.
223
+
224
+ ```ruby
225
+ @book.adapter_wrapper.class # => Book::AdapterWrapper
226
+ ```
227
+
228
+ And you can read the adapter internal method via it.
229
+
230
+ ```ruby
231
+ @book.adapter_wrapper.my_method # => works
232
+ ```
233
+
234
+ hmm... but i am not very recommend you to use it by this way,
235
+ if you need some method works alone,
236
+ maybe you should define it in the original class.
237
+
238
+ ### `link_one`
239
+
240
+ This method is a syntactic sugar of [`with`](#with), seems like
241
+
242
+ ```ruby
243
+ with :my_link do |*args|
244
+ my_link.adapter(*args)
245
+ end
246
+ ```
247
+
248
+ is equal with
249
+
250
+ ```ruby
251
+ link_one :my_link
252
+ ```
253
+
254
+ It usual used in one-to-one relationship like `belongs_to` in `rails`.
255
+
256
+ For example
257
+
258
+ ```ruby
259
+ # book.rb
260
+
261
+ belongs_to :book_shelf
262
+
263
+ define_adapter do
264
+ link_one :book_shelf
265
+
266
+ # ...
267
+ end
268
+
269
+ ```
270
+
271
+ ```ruby
272
+ # book_shelf.rb
273
+
274
+ define_adapter do
275
+
276
+ adapter do
277
+ {
278
+ id: id,
279
+ desc: desc,
280
+ }
281
+ end
282
+
283
+ end
284
+ ```
285
+
286
+ Then
287
+
288
+ ```ruby
289
+ @book.adapter(:book_shelf)
290
+ # => { id: 1, title: 'My Book', book_shelf: @book.book_shelf.adapter }
291
+ ```
292
+
293
+ Of course you can pass some arguments, and if you have several links,
294
+ they can also used in nested.
295
+
296
+ ```ruby
297
+ # ...
298
+
299
+ @book.adapter(book_shelf: [library: :some_method])
300
+ ```
301
+
302
+ And can define many links once.
303
+
304
+ ```ruby
305
+ # ...
306
+
307
+ link_one :my_link1, :my_link2
308
+ ```
309
+
310
+ ### `link_many`
311
+
312
+ Okay, this method is similar with [`link_one`](#link_one) but multiple.
313
+
314
+ If use `with` to implement likes
315
+
316
+ ```ruby
317
+ with :my_links do |*args|
318
+ my_links.map { |link| link.adapter(*args) }
319
+ end
320
+ ```
321
+
322
+ Usual used in one-to-many relationship, such as `has_many` in `rails`.
323
+
324
+ For example
325
+
326
+ ```ruby
327
+ # book.rb
328
+
329
+ has_many :categories
330
+
331
+ define_adapter do
332
+ link_many :categories
333
+
334
+ # ...
335
+ end
336
+
337
+ ```
338
+
339
+ ```ruby
340
+ # category.rb
341
+
342
+ define_adapter do
343
+
344
+ adapter do
345
+ {
346
+ id: id,
347
+ desc: desc,
348
+ }
349
+ end
350
+
351
+ end
352
+ ```
353
+
354
+ Then
355
+
356
+ ```ruby
357
+ @book.adapter(:categories)
358
+ # => { id: 1, title: 'My Book', categories: @book.categories.map(&:adapter) }
359
+ ```
360
+
361
+ Support multiple arguments and other usage, detail above.
data/build.sh ADDED
@@ -0,0 +1 @@
1
+ gem build client-data-adapter.gemspec
@@ -1,13 +1,16 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
1
4
  Gem::Specification.new do |s|
2
5
 
3
6
  s.name = 'client-data-adapter'
4
- s.version = '0.0.1'
5
- s.date = '2019-11-11'
6
- s.summary = 'client adapter'
7
- s.description = 'Adapter for data transfer to client.'
7
+ s.version = '0.1.0-beta.0'
8
+ s.summary = 'client data adapter'
9
+ s.description = 'For unify data formats to transfer to clients.'
8
10
  s.authors = ['shadow']
9
11
  s.files = `git ls-files`.split("\n")
10
- s.homepage = 'https://github.com/jinghua000/client-adapter'
12
+ s.homepage = 'https://github.com/jinghua000/client-data-adapter'
11
13
  s.license = 'MIT'
14
+ s.required_ruby_version = '>= 2.1'
12
15
 
13
16
  end
data/demo/book.rb ADDED
@@ -0,0 +1,81 @@
1
+ require_relative '../lib/client-data-adapter'
2
+ require_relative 'book_shelf'
3
+ require_relative 'category'
4
+
5
+ class Book
6
+
7
+ include ClientDataAdapter
8
+
9
+ define_adapter do
10
+
11
+ link_one :book_shelf
12
+ link_many :categories
13
+
14
+ adapter do
15
+ {
16
+ id: id,
17
+ title: title,
18
+ }
19
+ end
20
+
21
+ with :full_title do
22
+ "<#{title}>"
23
+ end
24
+
25
+ with :my_awesome_title do
26
+ "my_awesome_title"
27
+ end
28
+
29
+ with :pass1 do |*args|
30
+ args << 'pass1'
31
+ end
32
+
33
+ with :pass2 do |*args|
34
+ args << 'pass2'
35
+ end
36
+
37
+ with :id do
38
+ return id
39
+ end
40
+
41
+ end
42
+
43
+ attr_accessor :id, :title, :book_shelf_id
44
+
45
+ def initialize(**opt)
46
+
47
+ self.id = opt[:id]
48
+ self.title = opt[:title]
49
+ self.book_shelf_id = opt[:book_shelf_id]
50
+
51
+ end
52
+
53
+ def self.demo
54
+ new(
55
+ id: 1,
56
+ title: 'My Book',
57
+ book_shelf_id: 1,
58
+ )
59
+ end
60
+
61
+ def my_title
62
+ 'my title'
63
+ end
64
+
65
+ def my_awesome_title
66
+ 'no no no'
67
+ end
68
+
69
+ def sub_title(sub)
70
+ "#{title}-#{sub}"
71
+ end
72
+
73
+ def book_shelf
74
+ BookShelf.demo
75
+ end
76
+
77
+ def categories
78
+ [Category.new(id: 1, cat: 'one'), Category.new(id: 2, cat: 'two')]
79
+ end
80
+
81
+ end
@@ -0,0 +1,46 @@
1
+ require_relative 'library'
2
+
3
+ class BookShelf
4
+
5
+ include ClientDataAdapter
6
+
7
+ define_adapter do
8
+
9
+ link_one :library
10
+
11
+ adapter do
12
+ {
13
+ id: id,
14
+ desc: desc,
15
+ }
16
+ end
17
+
18
+ with :other_desc do
19
+ 'other desc'
20
+ end
21
+
22
+ end
23
+
24
+ attr_accessor :id, :desc, :library_id
25
+
26
+ def initialize(**opt)
27
+
28
+ self.id = opt[:id]
29
+ self.desc = opt[:desc]
30
+ self.library_id = opt[:library_id]
31
+
32
+ end
33
+
34
+ def self.demo
35
+ new(
36
+ id: 1,
37
+ desc: 'my book shelf',
38
+ library_id: 1,
39
+ )
40
+ end
41
+
42
+ def library
43
+ Library.demo
44
+ end
45
+
46
+ end
data/demo/category.rb ADDED
@@ -0,0 +1,29 @@
1
+ class Category
2
+
3
+ include ClientDataAdapter
4
+
5
+ define_adapter do
6
+
7
+ adapter do
8
+ {
9
+ id: id,
10
+ cat: cat,
11
+ }
12
+ end
13
+
14
+ end
15
+
16
+ attr_accessor :id, :cat
17
+
18
+ def initialize(**opt)
19
+
20
+ self.id = opt[:id]
21
+ self.cat = opt[:cat]
22
+
23
+ end
24
+
25
+ def summary
26
+ 'summary'
27
+ end
28
+
29
+ end
data/demo/library.rb ADDED
@@ -0,0 +1,36 @@
1
+ class Library
2
+
3
+ include ClientDataAdapter
4
+
5
+ define_adapter do
6
+
7
+ adapter do
8
+ {
9
+ id: id,
10
+ size: size,
11
+ }
12
+ end
13
+
14
+ with :welcome do
15
+ 'welcome'
16
+ end
17
+
18
+ end
19
+
20
+ attr_accessor :id, :size, :city_id
21
+
22
+ def initialize(**opt)
23
+
24
+ self.id = opt[:id]
25
+ self.size = opt[:size]
26
+
27
+ end
28
+
29
+ def self.demo
30
+ new(
31
+ id: 1,
32
+ size: 'small'
33
+ )
34
+ end
35
+
36
+ end
@@ -1,7 +1,11 @@
1
+ require_relative 'client-data-adapter/class_methods'
2
+ require_relative 'client-data-adapter/instance_methods'
3
+
1
4
  module ClientDataAdapter
2
5
 
3
- def self.demo
4
- 'hello'
6
+ def self.included(base)
7
+ base.include(ClientDataAdapter::InstanceMethods)
8
+ base.extend(ClientDataAdapter::ClassMethods)
5
9
  end
6
10
 
7
11
  end
@@ -0,0 +1,25 @@
1
+ require_relative 'config'
2
+ require_relative 'wrapper'
3
+
4
+ module ClientDataAdapter
5
+ module ClassMethods
6
+
7
+ # @yield define the adapter in the block
8
+ # @example
9
+ # define_adapter do
10
+ # # define your adapter here.
11
+ # # ...
12
+ # end
13
+ def define_adapter(&block)
14
+
15
+ const_set(ADAPTER_WRAPPER, Class.new(Wrapper))
16
+
17
+ # Return the wrapper of adapter.
18
+ define_method :adapter_wrapper do
19
+ @__adapter_wrapper__ ||= self.class.const_get(ADAPTER_WRAPPER).new(self, &block)
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ module ClientDataAdapter
2
+
3
+ ADAPTER_WRAPPER = :AdapterWrapper
4
+ ADAPTER = :adapter
5
+
6
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'util'
2
+
3
+ module ClientDataAdapter
4
+ module InstanceMethods
5
+
6
+ # Main adapter method.
7
+ #
8
+ # @param args [Symbol|String|Hash]
9
+ # @example
10
+ # @book.adapter(:method1, method2: 'payload', method3: [:foo, :bar])
11
+ def adapter(*args)
12
+
13
+ length = args.length
14
+
15
+ if length == 0
16
+ adapter_wrapper.__adapter__
17
+ else
18
+ Util.merge(
19
+ adapter_wrapper.__adapter__,
20
+ *args.map do |arg|
21
+ if [String, Symbol].include?(arg.class)
22
+ __merge_to_adapter__(arg.to_sym, nil)
23
+ elsif arg.is_a?(Hash)
24
+ arg.map { |k, v| __merge_to_adapter__(k, v) }
25
+ else
26
+ raise '[ERROR] Not available arguments type.'
27
+ end
28
+ end.flatten,
29
+ )
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def __merge_to_adapter__(key, params)
36
+ {}.tap do |hah|
37
+ hah["#{key}".to_sym] =
38
+ adapter_wrapper.respond_to?(key) ?
39
+ adapter_wrapper.public_send(key, *params) :
40
+ public_send(key, *params)
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ module ClientDataAdapter
2
+ module Util
3
+
4
+ module_function
5
+
6
+ # Merge some hash.
7
+ #
8
+ # @param [Hash] elements
9
+ def merge(*elements)
10
+ {}.tap do |hsh|
11
+ elements.each do |elem|
12
+ elem.each do |k, v|
13
+ hsh[k] = v
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ # Convert a Proc to Lambda.
20
+ #
21
+ # @param [Proc] source_proc
22
+ # @return [Lambda]
23
+ def to_lambda(source_proc)
24
+ return source_proc if source_proc.lambda?
25
+
26
+ unbound_method = Module.new.module_eval do
27
+ instance_method(define_method(:_, &source_proc))
28
+ end
29
+
30
+ lambda do |*args, &block|
31
+ unbound_method.bind(self).call(*args, &block)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,108 @@
1
+ require_relative 'util'
2
+
3
+ module ClientDataAdapter
4
+ class Wrapper
5
+
6
+ # Instance of original class.
7
+ #
8
+ # @example
9
+ # @book.adapter_wrapper.target == @book # => true
10
+ attr_reader :target
11
+
12
+ def initialize(target, &block)
13
+ @target = target
14
+
15
+ self.class.module_eval(&block)
16
+ end
17
+
18
+
19
+ # Main adapter method, should return +Hash+.
20
+ #
21
+ # Syntactic sugar of +with+.
22
+ #
23
+ # @return [Hash]
24
+ # @see with
25
+ # @example
26
+ # define_adapter do
27
+ #
28
+ # adapter do
29
+ # {
30
+ # id: id,
31
+ # title: title,
32
+ # }
33
+ # end
34
+ #
35
+ # end
36
+ def self.adapter(&block)
37
+ with('__adapter__', &block)
38
+ end
39
+
40
+ # Used in one-to-one relationship.
41
+ #
42
+ # Syntactic sugar of +with+.
43
+ #
44
+ # @param [Symbol] associations
45
+ # @see with
46
+ # @example
47
+ # define_adapter do
48
+ #
49
+ # link_one(:link1, :link2)
50
+ # # ...
51
+ #
52
+ # end
53
+ def self.link_one(*associations)
54
+ associations.each do |assoc|
55
+ with(assoc) do |*args|
56
+ public_send(assoc.to_sym).adapter(*args)
57
+ end
58
+ end
59
+ end
60
+
61
+ # Used in one-to-many relationship.
62
+ #
63
+ # Syntactic sugar of +with+.
64
+ #
65
+ # @param [Symbol] associations
66
+ # @see with
67
+ # @example
68
+ # define_adapter do
69
+ #
70
+ # link_many(:link1, :link2)
71
+ # # ...
72
+ #
73
+ # end
74
+ def self.link_many(*associations)
75
+ associations.each do |assoc|
76
+ with(assoc) do |*args|
77
+ public_send(assoc.to_sym).map do |elem|
78
+ elem.adapter(*args)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ # Define a method of +Wrapper+.
85
+ #
86
+ # Merged to the result of +adapter+ method.
87
+ #
88
+ # @param [Symbol] method_name
89
+ # @example
90
+ # define_adapter do
91
+ # # ...
92
+ #
93
+ # with :something do
94
+ # # do something
95
+ # end
96
+ #
97
+ # end
98
+ def self.with(method_name, &block)
99
+ define_method(method_name.to_sym) do |*args|
100
+ target.instance_exec(
101
+ *args,
102
+ &Util.to_lambda(block)
103
+ )
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,81 @@
1
+ require_relative '../demo/book'
2
+
3
+ RSpec.describe Book do
4
+
5
+ before(:each) do
6
+ @book = Book.demo
7
+ end
8
+
9
+ it "adapter method return adapter wrapper's __adapter__" do
10
+
11
+ expect(@book.adapter).to eq(id: @book.id, title: @book.title)
12
+ expect(@book.adapter).to eq(@book.adapter_wrapper.__adapter__)
13
+
14
+ end
15
+
16
+ it "adapter can contain `with` method's returns" do
17
+
18
+ expect(@book.adapter_wrapper.respond_to? :full_title).to eq(true)
19
+ expect(@book.adapter(:full_title))
20
+ .to eq(
21
+ id: @book.id,
22
+ title: @book.title,
23
+ full_title: @book.adapter_wrapper.full_title
24
+ )
25
+
26
+ end
27
+
28
+ it "adapter can contain origin class instance method" do
29
+
30
+ expect(@book.adapter_wrapper.respond_to? :my_title).to eq(false)
31
+ expect(@book.adapter(:my_title))
32
+ .to eq(
33
+ id: @book.id,
34
+ title: @book.title,
35
+ my_title: @book.my_title
36
+ )
37
+
38
+ end
39
+
40
+ it "methods inside adapter wrapper will override method outside" do
41
+
42
+ expect(@book.my_awesome_title).not_to eq(@book.adapter_wrapper.my_awesome_title)
43
+ expect(@book.adapter(:my_awesome_title))
44
+ .to eq(
45
+ id: @book.id,
46
+ title: @book.title,
47
+ my_awesome_title: @book.adapter_wrapper.my_awesome_title
48
+ )
49
+
50
+ end
51
+
52
+ it "adapter can pass arguments in `with` method block" do
53
+
54
+ expect(@book.adapter(pass1: [:a, :b, :c], pass2: [:x, :y, :z]))
55
+ .to eq(
56
+ id: @book.id,
57
+ title: @book.title,
58
+ pass1: @book.adapter_wrapper.pass1(*[:a, :b, :c]),
59
+ pass2: @book.adapter_wrapper.pass2(*[:x, :y, :z]),
60
+ )
61
+
62
+ end
63
+
64
+ it "adapter can pass arguments with origin class instance methods" do
65
+
66
+ expect(@book.adapter(sub_title: 'yes'))
67
+ .to eq(
68
+ id: @book.id,
69
+ title: @book.title,
70
+ sub_title: @book.sub_title('yes')
71
+ )
72
+
73
+ end
74
+
75
+ it "not available arguments type will raise an error" do
76
+
77
+ expect { @book.adapter(123) }.to raise_error(RuntimeError)
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../demo/book'
2
+
3
+ RSpec.describe Book do
4
+
5
+ before(:each) do
6
+ @book = Book.demo
7
+ end
8
+
9
+ it "adapter wrapper should apply origin instance's self-point" do
10
+
11
+ expect(@book.adapter_wrapper.target).to eq(@book)
12
+
13
+ end
14
+
15
+ it "adapter wrapper's methods can use return inside" do
16
+
17
+ expect(@book.adapter_wrapper.id).to eq(@book.id)
18
+
19
+ end
20
+
21
+ it "adapter wrapper named `AdapterWrapper`" do
22
+ expect(@book.adapter_wrapper.class).to eq(Book::AdapterWrapper)
23
+ end
24
+
25
+ end
data/spec/demo_spec.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative '../demo/book'
2
+
3
+ RSpec.describe Book do
4
+
5
+ end
data/spec/link_spec.rb ADDED
@@ -0,0 +1,104 @@
1
+ require_relative '../demo/book'
2
+
3
+ RSpec.describe Book do
4
+
5
+ before(:each) do
6
+ @book = Book.demo
7
+ end
8
+
9
+ it "link one should call linked target's adapter method" do
10
+
11
+ expect(@book.adapter(:book_shelf))
12
+ .to eq(
13
+ id: @book.id,
14
+ title: @book.title,
15
+ book_shelf: {
16
+ id: @book.book_shelf.id,
17
+ desc: @book.book_shelf.desc,
18
+ }
19
+ )
20
+
21
+ end
22
+
23
+ it "link one can pass arguments" do
24
+
25
+ expect(@book.adapter(book_shelf: :other_desc))
26
+ .to eq(
27
+ id: @book.id,
28
+ title: @book.title,
29
+ book_shelf: {
30
+ id: @book.book_shelf.id,
31
+ desc: @book.book_shelf.desc,
32
+ other_desc: @book.book_shelf.adapter_wrapper.other_desc,
33
+ }
34
+ )
35
+
36
+ end
37
+
38
+ it "link can be nested" do
39
+
40
+ @book_shelf = @book.book_shelf
41
+ @library = @book_shelf.library
42
+
43
+ expect(@book.adapter(book_shelf: [:other_desc, library: :welcome]))
44
+ .to eq(
45
+ id: @book.id,
46
+ title: @book.title,
47
+ book_shelf: {
48
+ id: @book_shelf.id,
49
+ desc: @book_shelf.desc,
50
+ other_desc: @book_shelf.adapter_wrapper.other_desc,
51
+ library: {
52
+ id: @library.id,
53
+ size: @library.size,
54
+ welcome: @library.adapter_wrapper.welcome,
55
+ },
56
+ }
57
+ )
58
+ end
59
+
60
+ it "link many should call all linked targets's adapter method" do
61
+
62
+ @categories = @book.categories
63
+ expect(@book.adapter(:categories))
64
+ .to eq(
65
+ id: @book.id,
66
+ title: @book.title,
67
+ categories: [
68
+ {
69
+ id: @categories[0].id,
70
+ cat: @categories[0].cat,
71
+ },
72
+ {
73
+ id: @categories[1].id,
74
+ cat: @categories[1].cat,
75
+ },
76
+ ]
77
+ )
78
+
79
+ end
80
+
81
+ it "link many can pass arguments" do
82
+
83
+ @categories = @book.categories
84
+ expect(@book.adapter(categories: :summary))
85
+ .to eq(
86
+ id: @book.id,
87
+ title: @book.title,
88
+ categories: [
89
+ {
90
+ id: @categories[0].id,
91
+ cat: @categories[0].cat,
92
+ summary: @categories[0].summary,
93
+ },
94
+ {
95
+ id: @categories[1].id,
96
+ cat: @categories[1].cat,
97
+ summary: @categories[1].summary,
98
+ },
99
+ ]
100
+ )
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,112 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+
17
+ require 'simplecov'
18
+ SimpleCov.start
19
+ SimpleCov.minimum_coverage 100
20
+
21
+ RSpec.configure do |config|
22
+ # rspec-expectations config goes here. You can use an alternate
23
+ # assertion/expectation library such as wrong or the stdlib/minitest
24
+ # assertions if you prefer.
25
+ config.expect_with :rspec do |expectations|
26
+ # This option will default to `true` in RSpec 4. It makes the `description`
27
+ # and `failure_message` of custom matchers include text for helper methods
28
+ # defined using `chain`, e.g.:
29
+ # be_bigger_than(2).and_smaller_than(4).description
30
+ # # => "be bigger than 2 and smaller than 4"
31
+ # ...rather than:
32
+ # # => "be bigger than 2"
33
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
34
+ end
35
+
36
+ # rspec-mocks config goes here. You can use an alternate test double
37
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
38
+ config.mock_with :rspec do |mocks|
39
+ # Prevents you from mocking or stubbing a method that does not exist on
40
+ # a real object. This is generally recommended, and will default to
41
+ # `true` in RSpec 4.
42
+ mocks.verify_partial_doubles = true
43
+ end
44
+
45
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
46
+ # have no way to turn it off -- the option exists only for backwards
47
+ # compatibility in RSpec 3). It causes shared context metadata to be
48
+ # inherited by the metadata hash of host groups and examples, rather than
49
+ # triggering implicit auto-inclusion in groups with matching metadata.
50
+ config.shared_context_metadata_behavior = :apply_to_host_groups
51
+
52
+ # The settings below are suggested to provide a good initial experience
53
+ # with RSpec, but feel free to customize to your heart's content.
54
+ =begin
55
+ # This allows you to limit a spec run to individual examples or groups
56
+ # you care about by tagging them with `:focus` metadata. When nothing
57
+ # is tagged with `:focus`, all examples get run. RSpec also provides
58
+ # aliases for `it`, `describe`, and `context` that include `:focus`
59
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
60
+ config.filter_run_when_matching :focus
61
+
62
+ # Allows RSpec to persist some state between runs in order to support
63
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
64
+ # you configure your source control system to ignore this file.
65
+ config.example_status_persistence_file_path = "spec/examples.txt"
66
+
67
+ # Limits the available syntax to the non-monkey patched syntax that is
68
+ # recommended. For more details, see:
69
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
70
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
71
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
72
+ config.disable_monkey_patching!
73
+
74
+ # This setting enables warnings. It's recommended, but in some cases may
75
+ # be too noisy due to issues in dependencies.
76
+ config.warnings = true
77
+
78
+ # Many RSpec users commonly either run the entire suite or an individual
79
+ # file, and it's useful to allow more verbose output when running an
80
+ # individual spec file.
81
+ if config.files_to_run.one?
82
+ # Use the documentation formatter for detailed output,
83
+ # unless a formatter has already been configured
84
+ # (e.g. via a command-line flag).
85
+ config.default_formatter = "doc"
86
+ end
87
+
88
+ # Print the 10 slowest examples and example groups at the
89
+ # end of the spec run, to help surface which specs are running
90
+ # particularly slow.
91
+ config.profile_examples = 10
92
+
93
+ # Run specs in random order to surface order dependencies. If you find an
94
+ # order dependency and want to debug it, you can fix the order by providing
95
+ # the seed, which is printed after each run.
96
+ # --seed 1234
97
+ config.order = :random
98
+
99
+ # Seed global randomization in this process using the `--seed` CLI option.
100
+ # Setting this allows you to use `--seed` to deterministically reproduce
101
+ # test failures related to randomization by passing the same `--seed` value
102
+ # as the one that triggered the failure.
103
+ Kernel.srand config.seed
104
+ =end
105
+ end
106
+
107
+ if ENV['IS_CI'].to_i == 1
108
+
109
+ require 'coveralls'
110
+ Coveralls.wear!
111
+
112
+ end
data/update.sh CHANGED
@@ -1,4 +1,4 @@
1
1
  git add .
2
- git commit -m 'update'
3
2
  git status
3
+ git commit -m 'update'
4
4
  git push origin dev
metadata CHANGED
@@ -1,27 +1,47 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: client-data-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0.pre.beta.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - shadow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-11 00:00:00.000000000 Z
11
+ date: 2019-11-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Adapter for data transfer to client.
13
+ description: For unify data formats to transfer to clients.
14
14
  email:
15
15
  executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".coveralls.yml"
19
20
  - ".gitignore"
21
+ - ".rspec"
22
+ - ".travis.yml"
23
+ - Gemfile
24
+ - LICENSE
20
25
  - README.md
26
+ - build.sh
21
27
  - client-data-adapter.gemspec
28
+ - demo/book.rb
29
+ - demo/book_shelf.rb
30
+ - demo/category.rb
31
+ - demo/library.rb
22
32
  - lib/client-data-adapter.rb
33
+ - lib/client-data-adapter/class_methods.rb
34
+ - lib/client-data-adapter/config.rb
35
+ - lib/client-data-adapter/instance_methods.rb
36
+ - lib/client-data-adapter/util.rb
37
+ - lib/client-data-adapter/wrapper.rb
38
+ - spec/adapter_spec.rb
39
+ - spec/adapter_wrapper_spec.rb
40
+ - spec/demo_spec.rb
41
+ - spec/link_spec.rb
42
+ - spec/spec_helper.rb
23
43
  - update.sh
24
- homepage: https://github.com/jinghua000/client-adapter
44
+ homepage: https://github.com/jinghua000/client-data-adapter
25
45
  licenses:
26
46
  - MIT
27
47
  metadata: {}
@@ -33,15 +53,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
33
53
  requirements:
34
54
  - - ">="
35
55
  - !ruby/object:Gem::Version
36
- version: '0'
56
+ version: '2.1'
37
57
  required_rubygems_version: !ruby/object:Gem::Requirement
38
58
  requirements:
39
- - - ">="
59
+ - - ">"
40
60
  - !ruby/object:Gem::Version
41
- version: '0'
61
+ version: 1.3.1
42
62
  requirements: []
43
63
  rubygems_version: 3.0.3
44
64
  signing_key:
45
65
  specification_version: 4
46
- summary: client adapter
66
+ summary: client data adapter
47
67
  test_files: []