remote_record 0.5.0 → 0.6.0

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: 4bf471bd03525a3f6dfdfedc1d88e2681264c85e98447607259fec7a94d56ddd
4
- data.tar.gz: 076113352a325ee80c09cca58a00cdd8e703a584392319f008393fdae90ddbc2
3
+ metadata.gz: 8b0ea2bc5ed71919334a2a22d53f70a38ad06b116c7e76679e76bb0aeeb9ec9c
4
+ data.tar.gz: 4874762ea7e61fc354e99faa8d4cf6e79ba9b1451dcf5eefb029e2c173911b13
5
5
  SHA512:
6
- metadata.gz: 3dc11719e885adf6220ef9b351b1605943ce25220c3e95ee0ee8820175685783777ed7f1bd43f22249f83cb95e8031509e2b85f8be04b65dc33aaab0c4fdca22
7
- data.tar.gz: 478180ddc5b281c7a9873313608ad62368f9c947125fd1095b1c61a88e9cce5147637ca1391c801a0af1c2f53e4ac34418256a38563893f926a4f55ee37d62b4
6
+ metadata.gz: 603cbf7ecd366f2e3ba00c0be7d1ef793a484948a4940ddae511ab7e99583620d405cee4068958099dcf44aec52bdcc0df612771fc9b9243db530b643d5f1220
7
+ data.tar.gz: d5edee74efd6afd30db89d237674c5deb6953279636accc3e22b28b95e866f769631dc4a13fa70b30982e8f1422f2707bd9ccac2b0b1bdca2de5824e21e9c732
data/README.md CHANGED
@@ -124,6 +124,105 @@ caching by way of expiry or ETags, I recommend using `faraday-http-cache` for
124
124
  your clients and setting `memoize` to `false`. Remote Record will eventually
125
125
  gain support for caching.
126
126
 
127
+ ### `remote_all` and `remote_where`
128
+
129
+ If you're able to fetch multiple records at once from the API, implement the
130
+ `self.all` method on your remote record class. This should return an array of
131
+ hashes that can be used to initialize a set of references.
132
+
133
+ This can optionally take a block
134
+ for authorization - note that it won't use the auth you've configured and that
135
+ you'll always have to supply that inline. For example:
136
+
137
+ ```ruby
138
+ module RemoteRecord
139
+ module GitHub
140
+ # :nodoc:
141
+ class User < RemoteRecord::Base
142
+ def get
143
+ client.user(remote_resource_id)
144
+ end
145
+
146
+ def self.all
147
+ Octokit::Client.new(access_token: yield).users
148
+ end
149
+
150
+ private
151
+
152
+ def client
153
+ Octokit::Client.new(access_token: authorization)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ ```
159
+
160
+ Now you can call `remote_all` on remote reference classes that use
161
+ `RemoteRecord::GitHub::User`, like this:
162
+
163
+ ```ruby
164
+ GitHub::UserReference.remote_all { GITHUB_PERSONAL_ACCESS_TOKEN }
165
+ ```
166
+
167
+ `remote_where` works in the same way, but with a parameter:
168
+
169
+ ```ruby
170
+ module RemoteRecord
171
+ module GitHub
172
+ # :nodoc:
173
+ class User < RemoteRecord::Base
174
+ def get
175
+ client.user(remote_resource_id)
176
+ end
177
+
178
+ def self.all
179
+ Octokit::Client.new(access_token: yield).users
180
+ end
181
+
182
+ def self.where(query)
183
+ Octokit::Client.new(access_token: yield).search_users(query)
184
+ end
185
+
186
+ private
187
+
188
+ def client
189
+ Octokit::Client.new(access_token: authorization)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ ```
195
+
196
+ Now you can call `remote_where` on remote reference classes that use
197
+ `RemoteRecord::GitHub::User`, like this:
198
+
199
+ ```ruby
200
+ GitHub::UserReference.remote_where('q=tom+repos:%3E42+followers:%3E1000') { GITHUB_PERSONAL_ACCESS_TOKEN }
201
+ ```
202
+
203
+ It's recommended that you include something in `self.where` to filter incoming
204
+ params. Ideally, you want to expose an interface that's as ActiveRecord-like as
205
+ possible, e.g.:
206
+
207
+ ```ruby
208
+ GitHub::UserReference.remote_where(q: 'tom', repos: '>42', followers: '>1000') { GITHUB_PERSONAL_ACCESS_TOKEN }
209
+ ```
210
+
211
+ It's recommended that you write a `Transformer` to do this. Check out
212
+ `RemoteRecord::Transformers::SnakeCase` for an example.
213
+
214
+ ### `initial_attrs`
215
+
216
+ Behind the scenes, `remote_all` initializes references with a set of
217
+ `initial_attrs`. You can do the same! If you've already fetched the data for an
218
+ object, just pass it to `new` for your reference class under the
219
+ `initial_attrs:` keyword parameter, like this:
220
+
221
+ ```ruby
222
+ todo = { id: 1, title: 'Hello world' }
223
+ TodoReference.new(remote_resource_id: todo[:id], initial_attrs: todo)
224
+ ```
225
+
127
226
  ### Forcing a fresh request
128
227
 
129
228
  You might want to force a fresh request in some instances, even if you're using
@@ -131,4 +230,6 @@ You might want to force a fresh request in some instances, even if you're using
131
230
 
132
231
  ### Skip fetching
133
232
 
134
- You might not want to make a request on initialize sometimes. In this case, pass `fetching: false` to your query or `new` to make sure the resource isn't fetched.
233
+ You might not want to make a request on initialize sometimes. In this case, pass
234
+ `fetching: false` to your query or `new` to make sure the resource isn't
235
+ fetched.
@@ -9,10 +9,10 @@ module RemoteRecord
9
9
  Config.defaults.merge(remote_record_class: self)
10
10
  end
11
11
 
12
- def initialize(reference, options)
12
+ def initialize(reference, options = default_config, initial_attrs = {})
13
13
  @reference = reference
14
- @options = options.presence || default_config
15
- @attrs = HashWithIndifferentAccess.new
14
+ @options = options
15
+ @attrs = HashWithIndifferentAccess.new(initial_attrs)
16
16
  end
17
17
 
18
18
  def method_missing(method_name, *_args, &_block)
@@ -29,6 +29,14 @@ module RemoteRecord
29
29
  raise NotImplementedError.new, '#get should return a hash of data that represents the remote record.'
30
30
  end
31
31
 
32
+ def self.all
33
+ raise NotImplementedError.new, '#all should return an array of hashes of data that represent remote records.'
34
+ end
35
+
36
+ def self.where(_params)
37
+ raise NotImplementedError.new, '#where should return an array of hashes of data that represent remote records.'
38
+ end
39
+
32
40
  def fetch
33
41
  @attrs.update(get)
34
42
  end
@@ -23,19 +23,37 @@ module RemoteRecord
23
23
  def remote_record_config
24
24
  Config.new
25
25
  end
26
+
27
+ def remote_all(&authz_proc)
28
+ remote_record_class.all(&authz_proc).map do |remote_resource|
29
+ where(remote_resource_id: remote_resource['id']).first_or_initialize(initial_attrs: remote_resource)
30
+ end
31
+ end
32
+
33
+ def remote_where(params, &authz_proc)
34
+ remote_record_class.where(params, &authz_proc).map do |remote_resource|
35
+ where(remote_resource_id: remote_resource['id']).first_or_initialize(initial_attrs: remote_resource)
36
+ end
37
+ end
26
38
  end
27
39
 
28
40
  # rubocop:disable Metrics/BlockLength
29
41
  included do
30
42
  include ActiveSupport::Rescuable
31
43
  attr_accessor :fetching
44
+ attr_accessor :initial_attrs
32
45
 
33
46
  after_initialize do |reference|
34
47
  reference.fetching = true if reference.fetching.nil?
48
+ reference.fetching = false if reference.initial_attrs.present?
35
49
  config = reference.class.remote_record_class.default_config.merge(
36
50
  reference.class.remote_record_config.to_h
37
51
  )
38
52
  reference.instance_variable_set('@remote_record_config', config)
53
+ reference.instance_variable_set('@instance',
54
+ @remote_record_config.remote_record_class.new(
55
+ self, @remote_record_config, reference.initial_attrs.presence || {}
56
+ ))
39
57
  reference.fetch_remote_resource
40
58
  end
41
59
 
@@ -4,8 +4,11 @@ module RemoteRecord
4
4
  module Transformers
5
5
  # Base transformer class. Inherit from this and implement `#transform`.
6
6
  class Base
7
- def initialize(data)
7
+ def initialize(data, direction = :up)
8
+ raise ArgumentError, 'The direction should be one of :up or :down.' unless %i[up down].include? direction
9
+
8
10
  @data = data
11
+ @direction = direction
9
12
  end
10
13
 
11
14
  def transform
@@ -15,14 +15,19 @@ module RemoteRecord
15
15
  when Array
16
16
  value.map { |v| convert_hash_keys(v) }
17
17
  when Hash
18
- Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }]
18
+ Hash[value.map { |k, v| [transform_key(k), convert_hash_keys(v)] }]
19
19
  else
20
20
  value
21
21
  end
22
22
  end
23
23
 
24
- def underscore_key(key)
25
- key.to_s.underscore.to_sym
24
+ def transform_key(key)
25
+ case @direction
26
+ when :up
27
+ key.to_s.underscore.to_sym
28
+ when :down
29
+ key.to_s.camelize(:lower).to_sym
30
+ end
26
31
  end
27
32
  end
28
33
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RemoteRecord
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remote_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Fish
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-01-12 00:00:00.000000000 Z
12
+ date: 2021-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -39,20 +39,6 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
- - !ruby/object:Gem::Dependency
43
- name: database_cleaner
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
42
  - !ruby/object:Gem::Dependency
57
43
  name: faraday
58
44
  requirement: !ruby/object:Gem::Requirement