active_git 0.0.7 → 0.0.8
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.
- 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
|