synchronisable 1.1.3 → 1.1.4
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 +4 -4
- data/Guardfile +0 -6
- data/TODO.md +3 -2
- data/lib/synchronisable/bootstrap/i18n.rb +11 -0
- data/lib/synchronisable/configuration.rb +0 -0
- data/lib/synchronisable/controller.rb +3 -3
- data/lib/synchronisable/gateway.rb +0 -2
- data/lib/synchronisable/input/descriptor.rb +54 -0
- data/lib/synchronisable/input/parser.rb +70 -0
- data/lib/synchronisable/version.rb +1 -1
- data/lib/synchronisable.rb +1 -10
- data/spec/dummy/app/gateways/stage_gateway.rb +22 -4
- data/spec/dummy/app/gateways/tournament_gateway.rb +10 -1
- data/spec/models/stage_spec.rb +5 -3
- data/spec/models/team_spec.rb +1 -1
- data/spec/spec_helper.rb +24 -30
- data/spec/synchronisable/synchronisable_spec.rb +17 -13
- data/synchronisable.gemspec +0 -1
- metadata +7 -19
- data/lib/synchronisable/input_descriptor.rb +0 -52
- data/lib/synchronisable/input_parser.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e53ab569c0106db0a2e1f17b9446111c8dde193
|
4
|
+
data.tar.gz: caebb67d58390fddd864b91a8e8901904f5094bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 209cee6e20cf9f5edd9b52e105e1c6a9db92beb0fd66a91e1a5841c10594ac41195b2708c6ab8f04776a431b03253c606f6a2185503c8e43b8ff9dd1db74525b
|
7
|
+
data.tar.gz: bd26bb9a7a7377ff5c3778b9ae3cce6525b99fccee41c4a113680dce94dcadd2bbeb5822141478ee33ca85250a4c2e570c3e26caa59dc9f6b6d5a02111565a6d
|
data/Guardfile
CHANGED
@@ -6,9 +6,3 @@ guard :rspec, :all_on_start => false, :all_after_pass => false do
|
|
6
6
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
7
|
watch('spec/spec_helper.rb') { "spec" }
|
8
8
|
end
|
9
|
-
|
10
|
-
|
11
|
-
guard 'spork' do
|
12
|
-
watch('Gemfile.lock')
|
13
|
-
watch('spec/spec_helper.rb') { :rspec }
|
14
|
-
end
|
data/TODO.md
CHANGED
@@ -17,6 +17,7 @@ Primary objectives
|
|
17
17
|
- [x] sync with ids array
|
18
18
|
- [ ] handle case when association type is a :hash
|
19
19
|
- [ ] sync method for collection proxy (Model.where(condition).sync)
|
20
|
+
- [ ] better specs for cases when we should fetch/find using complex params
|
20
21
|
|
21
22
|
Think about
|
22
23
|
======================================
|
@@ -27,7 +28,7 @@ Secondary objectives
|
|
27
28
|
======================================
|
28
29
|
- [x] option for verbose logging
|
29
30
|
- [x] colorized STDOUT
|
30
|
-
- [
|
31
|
+
- [x] actualize docs
|
31
32
|
|
32
33
|
|
33
34
|
The desired interface:
|
@@ -38,7 +39,7 @@ The desired interface:
|
|
38
39
|
```
|
39
40
|
|
40
41
|
```
|
41
|
-
Match.sync(:include => {
|
42
|
+
+ Match.sync(:include => {
|
42
43
|
:match_players => :player
|
43
44
|
})
|
44
45
|
+ Model.sync([id1, ..., idn])
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
|
3
|
+
locale_paths = File.join(File.dirname(__FILE__),
|
4
|
+
'..', 'locale', '*.yml')
|
5
|
+
|
6
|
+
Dir[locale_paths].each { |path| I18n.load_path << path }
|
7
|
+
I18n.backend.load_translations unless defined?(Rails)
|
8
|
+
|
9
|
+
I18n.config.enforce_available_locales = true
|
10
|
+
I18n.default_locale = :en
|
11
|
+
I18n.available_locales = [:en, :ru]
|
File without changes
|
@@ -2,7 +2,7 @@ require 'colorize'
|
|
2
2
|
|
3
3
|
require 'synchronisable/error_handler'
|
4
4
|
require 'synchronisable/context'
|
5
|
-
require 'synchronisable/
|
5
|
+
require 'synchronisable/input/parser'
|
6
6
|
require 'synchronisable/source'
|
7
7
|
require 'synchronisable/models/import'
|
8
8
|
require 'synchronisable/helper/logging'
|
@@ -77,7 +77,7 @@ module Synchronisable
|
|
77
77
|
#
|
78
78
|
# @return [Synchronisable::Context] synchronization context
|
79
79
|
#
|
80
|
-
# @see Synchronisable::
|
80
|
+
# @see Synchronisable::Input::Parser
|
81
81
|
def call(data)
|
82
82
|
sync do |context|
|
83
83
|
error_handler = ErrorHandler.new(logger, context)
|
@@ -116,7 +116,7 @@ module Synchronisable
|
|
116
116
|
@includes = options[:includes]
|
117
117
|
@parent = options[:parent]
|
118
118
|
|
119
|
-
@input =
|
119
|
+
@input = Input::Parser.new(@model, @synchronizer)
|
120
120
|
end
|
121
121
|
|
122
122
|
def sync
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Synchronisable
|
2
|
+
module Input
|
3
|
+
# Provides a set of helper methods
|
4
|
+
# to describe user input.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
# @see Synchronisable::Input::Descriptor
|
9
|
+
class Descriptor
|
10
|
+
attr_reader :data
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
@data = data
|
14
|
+
end
|
15
|
+
|
16
|
+
def empty?
|
17
|
+
@data.blank?
|
18
|
+
end
|
19
|
+
|
20
|
+
def params?
|
21
|
+
@data.is_a?(Hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
def remote_id?
|
25
|
+
@data.is_a?(String)
|
26
|
+
end
|
27
|
+
|
28
|
+
def local_id?
|
29
|
+
@data.is_a?(Integer)
|
30
|
+
end
|
31
|
+
|
32
|
+
def array_of_ids?
|
33
|
+
enumerable? && (
|
34
|
+
first_element.is_a?(String) ||
|
35
|
+
first_element.is_a?(Integer)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def element_class
|
40
|
+
first_element.try(:class)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def first_element
|
46
|
+
@data.try(:first)
|
47
|
+
end
|
48
|
+
|
49
|
+
def enumerable?
|
50
|
+
@data.is_a?(Enumerable)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'synchronisable/input/descriptor'
|
2
|
+
|
3
|
+
module Synchronisable
|
4
|
+
module Input
|
5
|
+
# Responsible for guessing the user input format.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
# @see Synchronisable::Input::Parser
|
10
|
+
class Parser
|
11
|
+
def initialize(model, synchronizer)
|
12
|
+
@model = model
|
13
|
+
@synchronizer = synchronizer
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parses the user input.
|
17
|
+
#
|
18
|
+
# @param data [Array<Hash>, Array<String>, Array<Integer>, String, Integer]
|
19
|
+
# synchronization data to handle.
|
20
|
+
#
|
21
|
+
# @return [Array<Hash>] array of hashes with remote attributes
|
22
|
+
def parse(data)
|
23
|
+
input = Descriptor.new(data)
|
24
|
+
|
25
|
+
result = case
|
26
|
+
when input.empty?
|
27
|
+
@synchronizer.fetch
|
28
|
+
when input.params?
|
29
|
+
find_or_fetch_by_params(input.data)
|
30
|
+
when input.remote_id?
|
31
|
+
@synchronizer.find(data)
|
32
|
+
when input.local_id?
|
33
|
+
find_by_local_id(data)
|
34
|
+
when input.array_of_ids?
|
35
|
+
find_by_array_of_ids(input)
|
36
|
+
else
|
37
|
+
result = data.dup
|
38
|
+
end
|
39
|
+
|
40
|
+
[result].flatten.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def find_or_fetch_by_params(params)
|
46
|
+
sync_method = params.key?(:id) ? :find : :fetch
|
47
|
+
@synchronizer.send(sync_method, params)
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_by_array_of_ids(input)
|
51
|
+
records = find_imports(input.element_class.name, input.data)
|
52
|
+
records.map { |r| @synchronizer.find(r.remote_id) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def find_by_local_id(id)
|
56
|
+
import = @model.find_by(id: id).try(:import)
|
57
|
+
import ? @synchronizer.find(import.remote_id) : nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_imports(class_name, ids)
|
61
|
+
case class_name
|
62
|
+
when 'Fixnum'
|
63
|
+
ids.map { |id| @model.find_by(id: id).try(&:import) }
|
64
|
+
when 'String'
|
65
|
+
ids.map { |id| Import.find_by(id: id) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/synchronisable.rb
CHANGED
@@ -8,7 +8,7 @@ require 'active_support/core_ext/string/inflections'
|
|
8
8
|
require 'active_support/configurable'
|
9
9
|
require 'active_support/concern'
|
10
10
|
|
11
|
-
require 'i18n'
|
11
|
+
require 'synchronisable/bootstrap/i18n'
|
12
12
|
|
13
13
|
require 'synchronisable/version'
|
14
14
|
require 'synchronisable/models/import'
|
@@ -16,15 +16,6 @@ require 'synchronisable/synchronizer'
|
|
16
16
|
require 'synchronisable/model'
|
17
17
|
require 'synchronisable/gateway'
|
18
18
|
|
19
|
-
locale_paths = File.join(File.dirname(__FILE__),
|
20
|
-
'synchronisable', 'locale', '*.yml')
|
21
|
-
|
22
|
-
Dir[locale_paths].each { |path| I18n.load_path << path }
|
23
|
-
I18n.backend.load_translations unless defined?(Rails)
|
24
|
-
|
25
|
-
I18n.config.enforce_available_locales = true
|
26
|
-
I18n.default_locale = :en
|
27
|
-
I18n.available_locales = [:en, :ru]
|
28
19
|
|
29
20
|
module Synchronisable
|
30
21
|
include ActiveSupport::Configurable
|
@@ -1,8 +1,4 @@
|
|
1
1
|
class StageGateway < GatewayBase
|
2
|
-
def id_key
|
3
|
-
:stage_id
|
4
|
-
end
|
5
|
-
|
6
2
|
def source
|
7
3
|
@source ||= [
|
8
4
|
FactoryGirl.build(:remote_stage,
|
@@ -15,4 +11,26 @@ class StageGateway < GatewayBase
|
|
15
11
|
)
|
16
12
|
]
|
17
13
|
end
|
14
|
+
|
15
|
+
def fetch(params)
|
16
|
+
tournament_id = params[:tournament_id]
|
17
|
+
|
18
|
+
raise "missed parameter 'tournament_id'" unless tournament_id
|
19
|
+
|
20
|
+
source.select do |attrs|
|
21
|
+
attrs[:tour_id] = tournament_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def find(params)
|
26
|
+
tournament_id, id = params[:tournament_id], params[:id]
|
27
|
+
|
28
|
+
raise "missed parameter 'tournament_id'" unless tournament_id
|
29
|
+
raise "missed parameter 'id'" unless id
|
30
|
+
|
31
|
+
source.find do |attrs|
|
32
|
+
attrs[:tour_id] = tournament_id &&
|
33
|
+
attrs[:stage_id] = id
|
34
|
+
end
|
35
|
+
end
|
18
36
|
end
|
@@ -8,7 +8,16 @@ class TournamentGateway < GatewayBase
|
|
8
8
|
FactoryGirl.build(:remote_tournament,
|
9
9
|
:tour_id => 'tournament_0',
|
10
10
|
:is_current => true,
|
11
|
-
:stages_ids =>
|
11
|
+
:stages_ids => [
|
12
|
+
{
|
13
|
+
id: 'stage_0',
|
14
|
+
tournament_id: 'tournament_0'
|
15
|
+
},
|
16
|
+
{
|
17
|
+
id: 'stage_1',
|
18
|
+
tournament_id: 'tournament_0'
|
19
|
+
}
|
20
|
+
]
|
12
21
|
)
|
13
22
|
]
|
14
23
|
end
|
data/spec/models/stage_spec.rb
CHANGED
@@ -11,10 +11,12 @@ describe Stage do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
describe 'skipping with before_sync hook' do
|
14
|
-
|
14
|
+
let!(:context) { Stage.sync(remote_attrs, :includes => {}) }
|
15
15
|
|
16
|
-
it
|
17
|
-
|
16
|
+
it 'skips hashes where name is "ignored"' do
|
17
|
+
expect(Stage.count).to eq(2)
|
18
|
+
expect(Synchronisable::Import.count).to eq(2)
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
data/spec/models/team_spec.rb
CHANGED
@@ -121,7 +121,7 @@ describe Team do
|
|
121
121
|
end
|
122
122
|
|
123
123
|
context 'when remote id is not specified in attributes hash' do
|
124
|
-
it
|
124
|
+
it 'return synchronization result that contains 1 error' do
|
125
125
|
result = Team.sync([remote_attrs.last])
|
126
126
|
expect(result.errors.count).to eq(1)
|
127
127
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,7 +6,6 @@ ENV['RAILS_ENV'] ||= 'test'
|
|
6
6
|
require 'database_cleaner'
|
7
7
|
require 'factory_girl'
|
8
8
|
require 'factory_girl_sequences'
|
9
|
-
require 'spork'
|
10
9
|
|
11
10
|
if ENV['COVERAGE']
|
12
11
|
require 'simplecov'
|
@@ -34,41 +33,36 @@ Dir[support_pattern].each { |file| require file }
|
|
34
33
|
|
35
34
|
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
DatabaseCleaner.clean_with(:truncation)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
config.before(:each) { DatabaseCleaner.strategy = :transaction }
|
53
|
-
|
54
|
-
config.before(:each, js: true) do
|
55
|
-
DatabaseCleaner.strategy = :truncation
|
36
|
+
RSpec.configure do |config|
|
37
|
+
config.run_all_when_everything_filtered = true
|
38
|
+
config.filter_run focus: true
|
39
|
+
config.order = 'random'
|
40
|
+
config.include FactoryGirl::Syntax::Methods
|
41
|
+
|
42
|
+
config.before(:suite) do
|
43
|
+
begin
|
44
|
+
FactoryGirl.lint
|
45
|
+
ensure
|
46
|
+
DatabaseCleaner.clean_with(:truncation)
|
56
47
|
end
|
48
|
+
end
|
57
49
|
|
58
|
-
|
59
|
-
config.after(:each) { DatabaseCleaner.clean }
|
50
|
+
config.before(:each) { DatabaseCleaner.strategy = :transaction }
|
60
51
|
|
61
|
-
|
62
|
-
|
63
|
-
end
|
52
|
+
config.before(:each, js: true) do
|
53
|
+
DatabaseCleaner.strategy = :truncation
|
64
54
|
end
|
65
55
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
56
|
+
config.before(:each) { DatabaseCleaner.start }
|
57
|
+
config.after(:each) { DatabaseCleaner.clean }
|
58
|
+
|
59
|
+
if ENV['RUN_SLOW_TESTS'] != 'true'
|
60
|
+
config.filter_run_excluding slow: true
|
70
61
|
end
|
71
62
|
end
|
72
63
|
|
73
|
-
|
64
|
+
FactoryGirl.define do
|
65
|
+
%w(remote match team player match_player stage tournament).each do |prefix|
|
66
|
+
sequence(:"#{prefix}_id") { |n| "#{prefix}_#{n}" }
|
67
|
+
end
|
74
68
|
end
|
@@ -23,7 +23,7 @@ describe Synchronisable do
|
|
23
23
|
context 'all' do
|
24
24
|
before :all do
|
25
25
|
Synchronisable.models = %w(
|
26
|
-
|
26
|
+
Tournament Team
|
27
27
|
Match MatchPlayer Player
|
28
28
|
)
|
29
29
|
end
|
@@ -38,21 +38,25 @@ describe Synchronisable do
|
|
38
38
|
it { is_expected.to change { Synchronisable::Import.count }.by(14) }
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
context 'when models setting is overriden in method call' do
|
42
|
+
before :all do
|
43
|
+
Synchronisable.models = %w(Team Match)
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
subject do
|
47
|
+
-> { Synchronisable.sync(Match, Player) }
|
48
|
+
end
|
49
|
+
|
50
|
+
it { is_expected.to change { Match.count }.by(1) }
|
51
|
+
it { is_expected.to change { Team.count }.by(2) }
|
52
|
+
it { is_expected.to change { Player.count }.by(4) }
|
53
|
+
it { is_expected.to change { MatchPlayer.count }.by(4) }
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
# it { is_expected.not_to change { Team.count }.by(2) }
|
55
|
+
it { is_expected.not_to change { Stage.count } }
|
56
|
+
it { is_expected.not_to change { Tournament.count } }
|
53
57
|
|
54
|
-
|
55
|
-
|
58
|
+
it { is_expected.to change { Synchronisable::Import.count }.by(11) }
|
59
|
+
end
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
data/synchronisable.gemspec
CHANGED
@@ -35,7 +35,6 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_development_dependency "database_cleaner"
|
36
36
|
spec.add_development_dependency "mutant"
|
37
37
|
spec.add_development_dependency "mutant-rspec"
|
38
|
-
spec.add_development_dependency "guard-spork"
|
39
38
|
spec.add_development_dependency "guard-rspec"
|
40
39
|
spec.add_development_dependency "simplecov"
|
41
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synchronisable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vasiliy Yorkin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -234,20 +234,6 @@ dependencies:
|
|
234
234
|
- - ">="
|
235
235
|
- !ruby/object:Gem::Version
|
236
236
|
version: '0'
|
237
|
-
- !ruby/object:Gem::Dependency
|
238
|
-
name: guard-spork
|
239
|
-
requirement: !ruby/object:Gem::Requirement
|
240
|
-
requirements:
|
241
|
-
- - ">="
|
242
|
-
- !ruby/object:Gem::Version
|
243
|
-
version: '0'
|
244
|
-
type: :development
|
245
|
-
prerelease: false
|
246
|
-
version_requirements: !ruby/object:Gem::Requirement
|
247
|
-
requirements:
|
248
|
-
- - ">="
|
249
|
-
- !ruby/object:Gem::Version
|
250
|
-
version: '0'
|
251
237
|
- !ruby/object:Gem::Dependency
|
252
238
|
name: guard-rspec
|
253
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -301,6 +287,8 @@ files:
|
|
301
287
|
- lib/generators/synchronisable/templates/initializer.rb
|
302
288
|
- lib/synchronisable.rb
|
303
289
|
- lib/synchronisable/attribute_mapper.rb
|
290
|
+
- lib/synchronisable/bootstrap/i18n.rb
|
291
|
+
- lib/synchronisable/configuration.rb
|
304
292
|
- lib/synchronisable/context.rb
|
305
293
|
- lib/synchronisable/controller.rb
|
306
294
|
- lib/synchronisable/dsl/associations.rb
|
@@ -316,8 +304,8 @@ files:
|
|
316
304
|
- lib/synchronisable/exceptions.rb
|
317
305
|
- lib/synchronisable/gateway.rb
|
318
306
|
- lib/synchronisable/helper/logging.rb
|
319
|
-
- lib/synchronisable/
|
320
|
-
- lib/synchronisable/
|
307
|
+
- lib/synchronisable/input/descriptor.rb
|
308
|
+
- lib/synchronisable/input/parser.rb
|
321
309
|
- lib/synchronisable/locale/en.yml
|
322
310
|
- lib/synchronisable/locale/ru.yml
|
323
311
|
- lib/synchronisable/model.rb
|
@@ -451,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
451
439
|
version: '0'
|
452
440
|
requirements: []
|
453
441
|
rubyforge_project:
|
454
|
-
rubygems_version: 2.2.
|
442
|
+
rubygems_version: 2.2.2
|
455
443
|
signing_key:
|
456
444
|
specification_version: 4
|
457
445
|
summary: Provides base fuctionality (models, DSL) for AR synchronization with external
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module Synchronisable
|
2
|
-
# Provides a set of helper methods
|
3
|
-
# to describe user input.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
#
|
7
|
-
# @see Synchronisable::InputParser
|
8
|
-
class InputDescriptor
|
9
|
-
attr_reader :data
|
10
|
-
|
11
|
-
def initialize(data)
|
12
|
-
@data = data
|
13
|
-
end
|
14
|
-
|
15
|
-
def empty?
|
16
|
-
@data.blank?
|
17
|
-
end
|
18
|
-
|
19
|
-
def params?
|
20
|
-
@data.is_a?(Hash)
|
21
|
-
end
|
22
|
-
|
23
|
-
def remote_id?
|
24
|
-
@data.is_a?(String)
|
25
|
-
end
|
26
|
-
|
27
|
-
def local_id?
|
28
|
-
@data.is_a?(Integer)
|
29
|
-
end
|
30
|
-
|
31
|
-
def array_of_ids?
|
32
|
-
enumerable? && (
|
33
|
-
first_element.is_a?(String) ||
|
34
|
-
first_element.is_a?(Integer)
|
35
|
-
)
|
36
|
-
end
|
37
|
-
|
38
|
-
def element_class
|
39
|
-
first_element.try(:class)
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def first_element
|
45
|
-
@data.try(:first)
|
46
|
-
end
|
47
|
-
|
48
|
-
def enumerable?
|
49
|
-
@data.is_a?(Enumerable)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'synchronisable/input_descriptor'
|
2
|
-
|
3
|
-
module Synchronisable
|
4
|
-
# Responsible for guessing the user input format.
|
5
|
-
#
|
6
|
-
# @api private
|
7
|
-
#
|
8
|
-
# @see Synchronisable::InputDescriptor
|
9
|
-
class InputParser
|
10
|
-
def initialize(model, synchronizer)
|
11
|
-
@model = model
|
12
|
-
@synchronizer = synchronizer
|
13
|
-
end
|
14
|
-
|
15
|
-
# Parses the user input.
|
16
|
-
#
|
17
|
-
# @param data [Array<Hash>, Array<String>, Array<Integer>, String, Integer]
|
18
|
-
# synchronization data to handle.
|
19
|
-
#
|
20
|
-
# @return [Array<Hash>] array of hashes with remote attributes
|
21
|
-
def parse(data)
|
22
|
-
input = InputDescriptor.new(data)
|
23
|
-
|
24
|
-
result = case
|
25
|
-
when input.empty?
|
26
|
-
@synchronizer.fetch
|
27
|
-
when input.params?
|
28
|
-
find_or_fetch_by_params(input.data)
|
29
|
-
when input.remote_id?
|
30
|
-
@synchronizer.find(data)
|
31
|
-
when input.local_id?
|
32
|
-
find_by_local_id(data)
|
33
|
-
when input.array_of_ids?
|
34
|
-
find_by_array_of_ids(input)
|
35
|
-
else
|
36
|
-
result = data.dup
|
37
|
-
end
|
38
|
-
|
39
|
-
[result].flatten.compact
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def find_or_fetch_by_params(params)
|
45
|
-
sync_method = params.key?(:id) ? :find : :fetch
|
46
|
-
@synchronizer.send(sync_method, params)
|
47
|
-
end
|
48
|
-
|
49
|
-
def find_by_array_of_ids(input)
|
50
|
-
records = find_imports(input.element_class.name, input.data)
|
51
|
-
records.map { |r| @synchronizer.find(r.remote_id) }
|
52
|
-
end
|
53
|
-
|
54
|
-
def find_by_local_id(id)
|
55
|
-
import = @model.find_by(id: id).try(:import)
|
56
|
-
import ? @synchronizer.find(import.remote_id) : nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def find_imports(class_name, ids)
|
60
|
-
case class_name
|
61
|
-
when 'Fixnum'
|
62
|
-
ids.map { |id| @model.find_by(id: id).try(&:import) }
|
63
|
-
when 'String'
|
64
|
-
ids.map { |id| Import.find_by(id: id) }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|