active_git 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/active_git/active_record_extension.rb +19 -15
- data/lib/active_git/commands.rb +1 -1
- data/lib/active_git/events/db_event.rb +4 -10
- data/lib/active_git/events/file_event.rb +2 -16
- data/lib/active_git/events/file_save.rb +1 -1
- data/lib/active_git/model_parser.rb +36 -0
- data/lib/active_git/version.rb +1 -1
- data/lib/active_git.rb +8 -3
- data/spec/active_record_extension_spec.rb +28 -8
- data/spec/batch_synchronization_spec.rb +5 -0
- data/spec/configuration_spec.rb +2 -2
- data/spec/json/dump.json +6 -0
- data/spec/json/nested_dump.json +24 -0
- data/spec/json/parent_child_dump.json +22 -0
- data/spec/migrations/20121004135939_create_countries.rb +1 -0
- data/spec/migrations/20130812112000_create_cities.rb +10 -0
- data/spec/model_parser_spec.rb +71 -0
- data/spec/support/models/city.rb +3 -0
- data/spec/support/models/country.rb +3 -0
- data/spec/support/models/language.rb +2 -1
- data/spec/synchronization_spec.rb +46 -1
- metadata +15 -2
@@ -3,7 +3,16 @@ module ActiveGit
|
|
3
3
|
|
4
4
|
module ClassMethods
|
5
5
|
|
6
|
-
def git_versioned
|
6
|
+
def git_versioned(options={})
|
7
|
+
|
8
|
+
@options = options.merge root: false
|
9
|
+
|
10
|
+
def git_options
|
11
|
+
@options
|
12
|
+
end
|
13
|
+
|
14
|
+
include InstanceMethods
|
15
|
+
|
7
16
|
ActiveGit.models << self
|
8
17
|
|
9
18
|
after_save do |record|
|
@@ -14,22 +23,17 @@ module ActiveGit
|
|
14
23
|
ActiveGit.synchronize FileDelete.new(record)
|
15
24
|
end
|
16
25
|
|
17
|
-
def from_json(json)
|
18
|
-
record = self.new
|
19
|
-
hash = json.is_a?(Hash) ? json : JSON.parse(json)
|
20
|
-
hash.each do |attr, value|
|
21
|
-
if record.respond_to? "#{attr}="
|
22
|
-
if self.columns_hash[attr].type == :datetime
|
23
|
-
record.send("#{attr}=", Time.parse(value).utc)
|
24
|
-
else
|
25
|
-
record.send("#{attr}=", value)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
record
|
30
|
-
end
|
31
26
|
end
|
32
27
|
|
33
28
|
end
|
29
|
+
|
30
|
+
module InstanceMethods
|
31
|
+
|
32
|
+
def git_dump
|
33
|
+
JSON.pretty_generate(as_json(self.class.git_options))
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
34
38
|
end
|
35
39
|
end
|
data/lib/active_git/commands.rb
CHANGED
@@ -6,10 +6,6 @@ module ActiveGit
|
|
6
6
|
@working_path = working_path || ActiveGit.configuration.working_path
|
7
7
|
end
|
8
8
|
|
9
|
-
def synchronize(synchronizer)
|
10
|
-
raise 'Must implement in subclass'
|
11
|
-
end
|
12
|
-
|
13
9
|
private
|
14
10
|
|
15
11
|
def model
|
@@ -20,13 +16,11 @@ module ActiveGit
|
|
20
16
|
Inflector.model_id @file_name
|
21
17
|
end
|
22
18
|
|
23
|
-
def data
|
24
|
-
json = File.open(@file_name, 'r') { |f| f.read }
|
25
|
-
model.from_json(json)
|
26
|
-
end
|
27
|
-
|
28
19
|
def create(synchronizer)
|
29
|
-
|
20
|
+
json = File.read(@file_name)
|
21
|
+
ModelParser.instances(model, json).each do |instance|
|
22
|
+
synchronizer.bulk_insert instance
|
23
|
+
end
|
30
24
|
end
|
31
25
|
|
32
26
|
def delete(synchronizer)
|
@@ -1,32 +1,18 @@
|
|
1
1
|
module ActiveGit
|
2
2
|
class FileEvent
|
3
3
|
|
4
|
+
attr_reader :data
|
5
|
+
|
4
6
|
def initialize(data, working_path=nil)
|
5
7
|
@data = data
|
6
8
|
@working_path = working_path || ActiveGit.configuration.working_path
|
7
9
|
end
|
8
10
|
|
9
|
-
def synchronize(synchronizer)
|
10
|
-
raise 'Must implement in subclass'
|
11
|
-
end
|
12
|
-
|
13
11
|
protected
|
14
12
|
|
15
|
-
def model
|
16
|
-
@data.class
|
17
|
-
end
|
18
|
-
|
19
|
-
def model_path
|
20
|
-
Inflector.dirname(model, @working_path)
|
21
|
-
end
|
22
|
-
|
23
13
|
def file_name
|
24
14
|
Inflector.filename(@data, @working_path)
|
25
15
|
end
|
26
16
|
|
27
|
-
def json
|
28
|
-
JSON.pretty_generate(@data.attributes)
|
29
|
-
end
|
30
|
-
|
31
17
|
end
|
32
18
|
end
|
@@ -5,7 +5,7 @@ module ActiveGit
|
|
5
5
|
synchronizer.define_job do
|
6
6
|
ActiveGit.configuration.logger.debug "[ActiveGit] Writing file #{file_name}"
|
7
7
|
FileUtils.mkpath(File.dirname(file_name)) unless Dir.exist?(File.dirname(file_name))
|
8
|
-
File.open(file_name, 'w') { |f| f.puts
|
8
|
+
File.open(file_name, 'w') { |f| f.puts data.git_dump }
|
9
9
|
end
|
10
10
|
|
11
11
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveGit
|
2
|
+
class ModelParser
|
3
|
+
|
4
|
+
def self.instances(model, json)
|
5
|
+
list = [from_json(model, json)]
|
6
|
+
attributes = json.is_a?(Hash) ? json : JSON.parse(json)
|
7
|
+
attributes.each do |attr, value|
|
8
|
+
if model.reflections.has_key?(attr.to_sym)
|
9
|
+
attr_model = attr.to_s.classify.constantize
|
10
|
+
if value.is_a? Array
|
11
|
+
value.each {|json| list = list + instances(attr_model, json)}
|
12
|
+
else
|
13
|
+
list = list + instances(attr_model, value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
list
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_json(model, json)
|
21
|
+
record = model.new
|
22
|
+
attributes = json.is_a?(Hash) ? json : JSON.parse(json)
|
23
|
+
attributes.each do |attr, value|
|
24
|
+
if model.column_names.include?(attr.to_s)
|
25
|
+
if model.columns_hash[attr.to_s].type == :datetime && value.is_a?(String)
|
26
|
+
record.send("#{attr}=", Time.parse(value).utc)
|
27
|
+
else
|
28
|
+
record.send("#{attr}=", value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
record
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/active_git/version.rb
CHANGED
data/lib/active_git.rb
CHANGED
@@ -21,6 +21,7 @@ require 'active_git/active_record_extension'
|
|
21
21
|
require 'active_git/configuration'
|
22
22
|
require 'active_git/commands'
|
23
23
|
require 'active_git/inflector'
|
24
|
+
require 'active_git/model_parser'
|
24
25
|
|
25
26
|
module ActiveGit
|
26
27
|
extend Commands
|
@@ -54,18 +55,22 @@ module ActiveGit
|
|
54
55
|
@batch_mode = true
|
55
56
|
begin
|
56
57
|
result = yield
|
57
|
-
Synchronizer.synchronize
|
58
|
+
Synchronizer.synchronize queued_events
|
58
59
|
result
|
59
60
|
ensure
|
60
61
|
@batch_mode = false
|
61
|
-
|
62
|
+
queued_events.clear
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
66
|
private
|
66
67
|
|
67
68
|
def self.enqueue(*events)
|
68
|
-
|
69
|
+
events.each { |e| queued_events << e }
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.queued_events
|
73
|
+
@events ||= []
|
69
74
|
end
|
70
75
|
|
71
76
|
end
|
@@ -48,14 +48,34 @@ describe ActiveGit::ActiveRecord do
|
|
48
48
|
File.exist?(git_filename(language)).should be false
|
49
49
|
end
|
50
50
|
|
51
|
-
it '
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
it 'Dump' do
|
52
|
+
Time.zone = 'Buenos Aires'
|
53
|
+
|
54
|
+
brand = Brand.new name: 'Brand 1',
|
55
|
+
created_at: Time.zone.parse('2012-04-20T11:24:11'),
|
56
|
+
updated_at: Time.zone.parse('2012-04-20T11:24:11')
|
57
|
+
|
58
|
+
brand.git_dump.should eq File.read("#{File.dirname(__FILE__)}/json/dump.json")
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'Nested dump' do
|
62
|
+
city = City.new name: 'Bs.As.'
|
63
|
+
country = Country.new name: 'Argentina'
|
64
|
+
country.cities << city
|
65
|
+
language = Language.new name: 'Spanish'
|
66
|
+
language.countries << country
|
67
|
+
|
68
|
+
language.git_dump.should eq File.read("#{File.dirname(__FILE__)}/json/nested_dump.json")
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'Parent and child dump' do
|
72
|
+
language = Language.new name: 'Spanish'
|
73
|
+
city = City.new name: 'Bs.As.'
|
74
|
+
country = Country.new name: 'Argentina'
|
75
|
+
country.cities << city
|
76
|
+
country.language = language
|
77
|
+
|
78
|
+
country.git_dump.should eq File.read("#{File.dirname(__FILE__)}/json/parent_child_dump.json")
|
59
79
|
end
|
60
80
|
|
61
81
|
end
|
@@ -113,6 +113,11 @@ describe ActiveGit do
|
|
113
113
|
File.exist?(git_filename(english)).should be true
|
114
114
|
end
|
115
115
|
|
116
|
+
it 'Batch process without events' do
|
117
|
+
Language.count.should eq 0
|
118
|
+
ActiveGit.batch {}
|
119
|
+
end
|
120
|
+
|
116
121
|
it 'Handle exceptions' do
|
117
122
|
spanish = nil
|
118
123
|
english = nil
|
data/spec/configuration_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe ActiveGit::Configuration do
|
|
13
13
|
ActiveGit.configuration.bare_path = @bare_path
|
14
14
|
ActiveGit.configuration.logger = @logger
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it 'default sync_batch_size' do
|
18
18
|
ActiveGit.configuration.sync_batch_size.should eq 10000
|
19
19
|
end
|
@@ -59,5 +59,5 @@ describe ActiveGit::Configuration do
|
|
59
59
|
ActiveGit.configuration.logger = logger
|
60
60
|
ActiveGit.configuration.logger.should eq logger
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
end
|
data/spec/json/dump.json
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"created_at": null,
|
3
|
+
"id": null,
|
4
|
+
"name": "Spanish",
|
5
|
+
"updated_at": null,
|
6
|
+
"countries": [
|
7
|
+
{
|
8
|
+
"created_at": null,
|
9
|
+
"id": null,
|
10
|
+
"language_id": null,
|
11
|
+
"name": "Argentina",
|
12
|
+
"updated_at": null,
|
13
|
+
"cities": [
|
14
|
+
{
|
15
|
+
"country_id": null,
|
16
|
+
"created_at": null,
|
17
|
+
"id": null,
|
18
|
+
"name": "Bs.As.",
|
19
|
+
"updated_at": null
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
23
|
+
]
|
24
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"created_at": null,
|
3
|
+
"id": null,
|
4
|
+
"language_id": null,
|
5
|
+
"name": "Argentina",
|
6
|
+
"updated_at": null,
|
7
|
+
"language": {
|
8
|
+
"created_at": null,
|
9
|
+
"id": null,
|
10
|
+
"name": "Spanish",
|
11
|
+
"updated_at": null
|
12
|
+
},
|
13
|
+
"cities": [
|
14
|
+
{
|
15
|
+
"country_id": null,
|
16
|
+
"created_at": null,
|
17
|
+
"id": null,
|
18
|
+
"name": "Bs.As.",
|
19
|
+
"updated_at": null
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveGit::ModelParser do
|
4
|
+
|
5
|
+
LANGUAGE = {
|
6
|
+
id: 1,
|
7
|
+
name: 'Spanish',
|
8
|
+
created_at: Time.now,
|
9
|
+
updated_at: Time.now,
|
10
|
+
countries: [
|
11
|
+
{
|
12
|
+
id: 1,
|
13
|
+
name: 'Argentina',
|
14
|
+
LANGUAGE_id: 1,
|
15
|
+
cities: [
|
16
|
+
{id: 1, name: 'Buenos Aires', country_id: 1},
|
17
|
+
{id: 2, name: 'Rosario', country_id: 1}
|
18
|
+
]
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
22
|
+
|
23
|
+
[LANGUAGE, LANGUAGE.to_json].each do |source|
|
24
|
+
it "Load from #{source.class.to_s.downcase}" do
|
25
|
+
instance = ActiveGit::ModelParser.from_json(Language, source)
|
26
|
+
|
27
|
+
instance.id.should eq LANGUAGE[:id]
|
28
|
+
instance.name.should eq LANGUAGE[:name]
|
29
|
+
instance.created_at.to_i.should eq LANGUAGE[:created_at].to_i
|
30
|
+
instance.updated_at.to_i.should eq LANGUAGE[:updated_at].to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
it "Instances from #{source.class.to_s.downcase}" do
|
34
|
+
instances = ActiveGit::ModelParser.instances(Language, source)
|
35
|
+
|
36
|
+
instances.count.should eq 4
|
37
|
+
instances[0].class.should eq Language
|
38
|
+
instances[0].name.should eq 'Spanish'
|
39
|
+
instances[1].class.should eq Country
|
40
|
+
instances[1].name.should eq 'Argentina'
|
41
|
+
instances[2].class.should eq City
|
42
|
+
instances[2].name.should eq 'Buenos Aires'
|
43
|
+
instances[3].class.should eq City
|
44
|
+
instances[3].name.should eq 'Rosario'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "instances from a hash with different associations" do
|
49
|
+
country = {
|
50
|
+
id: 1,
|
51
|
+
name: 'Argentina',
|
52
|
+
language: {id: 1, name: 'Spanish'},
|
53
|
+
cities: [
|
54
|
+
{id: 1, name: 'Buenos Aires', country_id: 1},
|
55
|
+
{id: 2, name: 'Rosario', country_id: 1}
|
56
|
+
]
|
57
|
+
}
|
58
|
+
|
59
|
+
instances = ActiveGit::ModelParser.instances(Country, country)
|
60
|
+
instances.count.should eq 4
|
61
|
+
instances[0].class.should eq Country
|
62
|
+
instances[0].name.should eq 'Argentina'
|
63
|
+
instances[1].class.should eq Language
|
64
|
+
instances[1].name.should eq 'Spanish'
|
65
|
+
instances[2].class.should eq City
|
66
|
+
instances[2].name.should eq 'Buenos Aires'
|
67
|
+
instances[3].class.should eq City
|
68
|
+
instances[3].name.should eq 'Rosario'
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -62,7 +62,7 @@ describe ActiveGit::Synchronizer do
|
|
62
62
|
working_path = @file_helper.create_temp_folder
|
63
63
|
|
64
64
|
file_name = "#{working_path}/countries/1.json"
|
65
|
-
@file_helper.write_file file_name, {id: 1, name: 'Argentina', created_at:
|
65
|
+
@file_helper.write_file file_name, {id: 1, name: 'Argentina', created_at: Time.now, updated_at: Time.now}.to_json
|
66
66
|
|
67
67
|
Country.count.should eq 0
|
68
68
|
|
@@ -71,6 +71,51 @@ describe ActiveGit::Synchronizer do
|
|
71
71
|
Country.find(1).name.should eq 'Argentina'
|
72
72
|
end
|
73
73
|
|
74
|
+
it 'Create multiple models from a file with 3 nested levels' do
|
75
|
+
working_path = @file_helper.create_temp_folder
|
76
|
+
|
77
|
+
city1_json = {id: 1, name: "Buenos Aires", country_id: 1, created_at: Time.now, updated_at: Time.now}
|
78
|
+
city2_json = {id: 2, name: "Rosario", country_id: 1, created_at: Time.now, updated_at: Time.now}
|
79
|
+
country1_json = {id: 1, name: 'Argentina', language_id: 1, created_at: Time.now, updated_at: Time.now, cities:[city1_json,city2_json]}
|
80
|
+
|
81
|
+
city1_json = {id: 3, name: "Montevideo", country_id: 2, created_at: Time.now, updated_at: Time.now}
|
82
|
+
city2_json = {id: 4, name: "Colonia", country_id: 2, created_at: Time.now, updated_at: Time.now}
|
83
|
+
country2_json = {id: 2, name: 'Uruguay', language_id: 1, created_at: Time.now, updated_at: Time.now, cities:[city1_json,city2_json]}
|
84
|
+
|
85
|
+
file_name = "#{working_path}/languages/1.json"
|
86
|
+
@file_helper.write_file file_name, {id: 1, name: 'Spanish', created_at: Time.now, updated_at: Time.now, countries:[country1_json,country2_json] }.to_json
|
87
|
+
|
88
|
+
Language.count.should eq 0
|
89
|
+
Country.count.should eq 0
|
90
|
+
City.count.should eq 0
|
91
|
+
|
92
|
+
ActiveGit::Synchronizer.synchronize ActiveGit::DbCreate.new(file_name, working_path)
|
93
|
+
|
94
|
+
Language.count.should eq 1
|
95
|
+
Country.count.should eq 2
|
96
|
+
City.count.should eq 4
|
97
|
+
|
98
|
+
spanish = Language.find_by_name 'Spanish'
|
99
|
+
|
100
|
+
spanish.countries.count.should eq 2
|
101
|
+
spanish.countries.should include(Country.find_by_name 'Argentina')
|
102
|
+
spanish.countries.should include(Country.find_by_name 'Uruguay')
|
103
|
+
|
104
|
+
argentina = Country.find_by_name 'Argentina'
|
105
|
+
|
106
|
+
argentina.cities.count.should eq 2
|
107
|
+
argentina.cities.should include(City.find_by_name 'Buenos Aires')
|
108
|
+
argentina.cities.should include(City.find_by_name 'Rosario')
|
109
|
+
argentina.cities.should_not include(City.find_by_name 'Montevideo')
|
110
|
+
|
111
|
+
uruguay = Country.find_by_name 'Uruguay'
|
112
|
+
|
113
|
+
uruguay.cities.count.should eq 2
|
114
|
+
uruguay.cities.should include(City.find_by_name 'Montevideo')
|
115
|
+
uruguay.cities.should include(City.find_by_name 'Colonia')
|
116
|
+
uruguay.cities.should_not include(City.find_by_name 'Buenos Aires')
|
117
|
+
end
|
118
|
+
|
74
119
|
it 'Update' do
|
75
120
|
working_path = @file_helper.create_temp_folder
|
76
121
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_git
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -200,6 +200,7 @@ files:
|
|
200
200
|
- lib/active_git/events/file_save.rb
|
201
201
|
- lib/active_git/events/folder_remove.rb
|
202
202
|
- lib/active_git/inflector.rb
|
203
|
+
- lib/active_git/model_parser.rb
|
203
204
|
- lib/active_git/synchronization_error.rb
|
204
205
|
- lib/active_git/synchronizer.rb
|
205
206
|
- lib/active_git/version.rb
|
@@ -209,13 +210,19 @@ files:
|
|
209
210
|
- spec/configuration_spec.rb
|
210
211
|
- spec/coverage_helper.rb
|
211
212
|
- spec/inflector_spec.rb
|
213
|
+
- spec/json/dump.json
|
214
|
+
- spec/json/nested_dump.json
|
215
|
+
- spec/json/parent_child_dump.json
|
212
216
|
- spec/migrations/20121004135939_create_countries.rb
|
213
217
|
- spec/migrations/20121004135940_create_languages.rb
|
214
218
|
- spec/migrations/20121030163114_create_brands.rb
|
215
219
|
- spec/migrations/20130315192821_create_customers.rb
|
220
|
+
- spec/migrations/20130812112000_create_cities.rb
|
221
|
+
- spec/model_parser_spec.rb
|
216
222
|
- spec/spec_helper.rb
|
217
223
|
- spec/support/helpers/file_helper.rb
|
218
224
|
- spec/support/models/brand.rb
|
225
|
+
- spec/support/models/city.rb
|
219
226
|
- spec/support/models/country.rb
|
220
227
|
- spec/support/models/customer.rb
|
221
228
|
- spec/support/models/language.rb
|
@@ -251,13 +258,19 @@ test_files:
|
|
251
258
|
- spec/configuration_spec.rb
|
252
259
|
- spec/coverage_helper.rb
|
253
260
|
- spec/inflector_spec.rb
|
261
|
+
- spec/json/dump.json
|
262
|
+
- spec/json/nested_dump.json
|
263
|
+
- spec/json/parent_child_dump.json
|
254
264
|
- spec/migrations/20121004135939_create_countries.rb
|
255
265
|
- spec/migrations/20121004135940_create_languages.rb
|
256
266
|
- spec/migrations/20121030163114_create_brands.rb
|
257
267
|
- spec/migrations/20130315192821_create_customers.rb
|
268
|
+
- spec/migrations/20130812112000_create_cities.rb
|
269
|
+
- spec/model_parser_spec.rb
|
258
270
|
- spec/spec_helper.rb
|
259
271
|
- spec/support/helpers/file_helper.rb
|
260
272
|
- spec/support/models/brand.rb
|
273
|
+
- spec/support/models/city.rb
|
261
274
|
- spec/support/models/country.rb
|
262
275
|
- spec/support/models/customer.rb
|
263
276
|
- spec/support/models/language.rb
|