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.
@@ -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
@@ -84,7 +84,7 @@ module ActiveGit
84
84
 
85
85
  model = File.dirname(file_name).split(/\/|\\/).pop.classify.constantize
86
86
 
87
- FileSave.new(model.from_json(merge))
87
+ FileSave.new(ModelParser.from_json(model, merge))
88
88
  end
89
89
 
90
90
  Synchronizer.synchronize events
@@ -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
- synchronizer.bulk_insert data
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 json }
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
@@ -1,3 +1,3 @@
1
1
  module ActiveGit
2
- VERSION = '0.0.7'
2
+ VERSION = '0.0.8'
3
3
  end
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 @events
58
+ Synchronizer.synchronize queued_events
58
59
  result
59
60
  ensure
60
61
  @batch_mode = false
61
- @events.clear if @events
62
+ queued_events.clear
62
63
  end
63
64
  end
64
65
 
65
66
  private
66
67
 
67
68
  def self.enqueue(*events)
68
- @events = (@events || []) + events
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 'Load from json' do
52
- attributes = {id: 1, name: 'Spanish', created_at: Time.now, updated_at: Time.now}
53
- language = Language.from_json attributes.to_json
54
-
55
- language.id.should eq attributes[:id]
56
- language.name.should eq attributes[:name]
57
- language.created_at.to_i.should eq attributes[:created_at].to_i
58
- language.updated_at.to_i.should eq attributes[:updated_at].to_i
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
@@ -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
@@ -0,0 +1,6 @@
1
+ {
2
+ "created_at": "2012-04-20T11:24:11-03:00",
3
+ "id": null,
4
+ "name": "Brand 1",
5
+ "updated_at": "2012-04-20T11:24:11-03:00"
6
+ }
@@ -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
+ }
@@ -2,6 +2,7 @@ class CreateCountries < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :countries do |t|
4
4
  t.string :name, null: false
5
+ t.references :language
5
6
 
6
7
  t.timestamps
7
8
  end
@@ -0,0 +1,10 @@
1
+ class CreateCities < ActiveRecord::Migration
2
+ def change
3
+ create_table :cities do |t|
4
+ t.string :name, null: false
5
+ t.references :country
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ class City < ActiveRecord::Base
2
+ belongs_to :country
3
+ end
@@ -1,2 +1,5 @@
1
1
  class Country < ActiveRecord::Base
2
+ git_versioned include: [:language, :cities]
3
+ belongs_to :language
4
+ has_many :cities
2
5
  end
@@ -1,3 +1,4 @@
1
1
  class Language < ActiveRecord::Base
2
- git_versioned
2
+ git_versioned(include: {countries: {include: :cities}})
3
+ has_many :countries
3
4
  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: '2012-04-20T11:24:11-03:00', updated_at: '2012-04-20T11:24:11-03:00'}.to_json
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.7
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-09 00:00:00.000000000 Z
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