swim 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
File without changes
data/.rspec CHANGED
File without changes
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in swim.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'rake'
6
7
  gem 'activesupport'
7
8
  gem 'activerecord'
8
- gem "sqlite3"
9
+ gem 'multi_json'
data/LICENSE CHANGED
File without changes
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Swim
2
2
 
3
- TODO: Write a gem description
3
+ Swim provides tools for synchronizing a tree of ActiveRecord objects with a previously-saved JSON file.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,7 +18,21 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ 1. Add a settings_file instance method to your ActiveRecord class.
22
+
23
+ class Artist < ActiveRecord::Base
24
+ def settings_file
25
+ File.expand_path("/sample_files/artist_1_settings.json")
26
+ end
27
+ end
28
+
29
+ 2. Add a sync_settings class method to your ActiveRecord class.
30
+
31
+ class Artist < ActiveRecord::Base
32
+ def self.sync_settings
33
+ { :albums => {} }
34
+ end
35
+ end
22
36
 
23
37
  ## Contributing
24
38
 
data/lib/swim.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'multi_json'
2
+
1
3
  module Swim
2
4
  require "swim/version"
3
5
  require "swim/change"
data/lib/swim/change.rb CHANGED
@@ -1,37 +1,36 @@
1
+ # Class to store changes made during SyncTools' import_json_file method.
1
2
  class Swim::Change
2
3
  attr_accessor :obj_class, :obj_id, :change_type, :key, :old_value, :new_value, :status, :errors
3
-
4
- def initialize(args)
5
- obj_class = args[:obj_class]
6
- obj_id = args[:obj_id]
7
- change_type = args[:change_type]
8
- key = args[:key]
9
- old_value = args[:old_value]
10
- new_value = args[:new_value]
11
- status = args[:status]
12
- errors = args[:errors]
13
- end
14
-
15
- def new(args)
16
- end
17
-
18
- def item
19
- obj_class.constantize.send(:find, obj_id)
20
- end
21
-
22
- def update(i)
23
- i.update_attribute(key, new_value)
4
+
5
+ def initialize(attributes = nil)
6
+ self.obj_class = attributes[:obj_class]
7
+ self.obj_id = attributes[:obj_id]
8
+ self.change_type = attributes[:change_type]
9
+ self.key = attributes[:key]
10
+ self.old_value = attributes[:old_value]
11
+ self.new_value = attributes[:new_value]
12
+ self.status = attributes[:status]
13
+ self.errors = attributes[:errors]
24
14
  end
25
15
 
26
- def delete(i)
27
- i.destroy
16
+ def to_s
17
+ if status.nil? || status.empty?
18
+ verb = "would be"
19
+ elsif status == "succeeded"
20
+ verb = "was"
21
+ elsif status == "failed"
22
+ verb = "could not be"
23
+ end
24
+ if change_type == :update
25
+ "#{obj_class}(#{obj_id})##{key} #{verb} #{old_value} (instead of #{new_value})."
26
+ else
27
+ "#{obj_class}(#{obj_id}) #{verb} #{change_type}d (#{ change_type == :insert ? new_value.to_hash : old_value.to_hash })."
28
+ end
28
29
  end
29
30
 
30
- def insert
31
- i = obj_class.constantize.send(:new, new_value)
32
- return i
31
+ def new(args)
33
32
  end
34
-
33
+
35
34
  def process
36
35
  if change_type == :update
37
36
  i = item
@@ -55,4 +54,27 @@ class Swim::Change
55
54
  return false
56
55
  end
57
56
  end
57
+
58
+ private
59
+
60
+ # Convenience method for accessing the changed object in the database
61
+ def item
62
+ obj_class.constantize.send(:find, obj_id)
63
+ end
64
+
65
+ # Method to execute the attribute update described by the Change
66
+ def update(i)
67
+ i.update_attribute(key, new_value)
68
+ end
69
+
70
+ # Method to execute the object deletion described by the Change
71
+ def delete(i)
72
+ i.destroy
73
+ end
74
+
75
+ # Method to execute the object insertion described by the Change
76
+ def insert
77
+ i = obj_class.constantize.send(:new, new_value)
78
+ return i
79
+ end
58
80
  end
@@ -1,25 +1,31 @@
1
- require 'active_support/all'
2
-
3
1
  class SyncSettingsMissing < StandardError
4
2
  end
5
3
 
6
- class SettingsFileMissing < StandardError
4
+ class SettingsPathMissing < StandardError
5
+ end
6
+
7
+ class ComparisonHashMissing < StandardError
8
+ end
9
+
10
+ class InvalidSettingsPath < StandardError
7
11
  end
8
12
 
9
13
 
14
+ # Tools for syncing a tree of ActiveRecord objects using a JSON file.
10
15
  class SyncTools
11
-
12
- def self.json_file(settings_filename)
13
- file = File.open(settings_filename, "rb")
14
- contents = file.read
15
- ActiveSupport::JSON.decode(contents)
16
+
17
+ # Save a JSON representaton of the object to a file, specified by
18
+ def self.save_settings(obj)
19
+ str = obj.to_json(:include => obj.class.sync_settings )
20
+ File.open(File.expand_path(obj.settings_path), 'w+') {|f| f.write(str) }
16
21
  end
17
-
22
+
23
+ # compares a tree of ActiveRecord objects to a previously-saved JSON file
18
24
  def self.compare_json_file(obj)
19
- unless obj.methods.include?(:settings_file) || obj.methods.include?('settings_file')
20
- raise SettingsFileMissing, "#{obj.class.to_s} must define a class method named settings_file."
25
+ unless obj.methods.include?(:settings_path) || obj.methods.include?('settings_path')
26
+ raise SettingsPathMissing, "#{obj.class.to_s} must define a class method named settings_file."
21
27
  end
22
- json = json_file(obj.settings_file)
28
+ json = json_file(File.expand_path(obj.settings_path))
23
29
 
24
30
  unless obj.class.methods.include?(:sync_settings) || obj.class.methods.include?("sync_settings")
25
31
  raise SyncSettingsMissing, "#{obj.class.to_s} must define a class method named sync_settings that returns a hash."
@@ -32,8 +38,8 @@ class SyncTools
32
38
  end
33
39
  end
34
40
 
35
- def self.import_json_file(obj, settings_filename)
36
- changes = Swim::SyncTools.compare_json_file(self, settings_file)
41
+ def self.import_json_file(obj, settings_path)
42
+ changes = Swim::SyncTools.compare_json_file(self, settings_path)
37
43
  completed = []
38
44
  not_completed = []
39
45
  changes.each do |ch|
@@ -72,6 +78,7 @@ class SyncTools
72
78
  value = value.utc.to_s
73
79
  end
74
80
  unless value == hsh_value
81
+ # p "#{obj.class.to_s} #{obj.id} #{key} #{value} != #{hsh_value}"
75
82
  @changes << Swim::Change.new(:obj_class => obj.class.to_s, :obj_id => obj.id, :change_type => :update, :key => key, :old_value => value, :new_value => hsh_value)
76
83
  else
77
84
  # p "#{obj.class.to_s} #{key} #{value} == #{hsh_value}"
@@ -84,7 +91,7 @@ class SyncTools
84
91
  if arr.length == 0 && hsh.nil?
85
92
  return
86
93
  elsif hsh.nil?
87
- throw "Array (#{arr.collect{|ar| ar.class.to_s }}) has no hash for comparison"
94
+ raise ComparisonHashMissing, "Array (#{arr.collect{|ar| ar.class.to_s }}) has no hash for comparison"
88
95
  end
89
96
  hsh_members = hsh.collect{ |h| h["id"] }
90
97
  arr.each do |a|
@@ -102,5 +109,11 @@ class SyncTools
102
109
  end
103
110
  end
104
111
  end
105
-
112
+
113
+ # loads and decodes a specified json_file
114
+ def self.json_file(settings_path)
115
+ file = File.open(settings_path, "rb")
116
+ contents = file.read
117
+ ActiveSupport::JSON.decode(contents)
118
+ end
106
119
  end
data/lib/swim/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Swim
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
File without changes
File without changes
@@ -3,47 +3,55 @@ require 'spec_helper'
3
3
  require 'swim/change'
4
4
  require 'swim/sync_tools'
5
5
 
6
- class AlmostValidClass
7
- def settings_file
8
- File.expand_path("#{__FILE__}/../../sample_files/almost_valid_class_settings.json")
9
- end
10
-
11
- # def self.sync_settings
12
- # return Hash.new
13
- # end
14
- end
15
-
16
- class InvalidClass
17
- # def self.settings_file
18
- # return Hash.new
19
- # end
20
- # def self.sync_settings
21
- # return Hash.new
22
- # end
23
- end
24
-
25
6
  describe SyncTools do
26
7
 
27
- it "should require the object to define settings_file" do
28
- i_class = InvalidClass.new
29
- expect { SyncTools::compare_json_file(i_class) }.to raise_error(
30
- SettingsFileMissing
31
- )
8
+ context "necessary settings" do
9
+ it "should require the object to define settings_path" do
10
+ expect { SyncTools::compare_json_file(InvalidClass.new) }.to raise_error(
11
+ SettingsPathMissing
12
+ )
13
+ end
14
+
15
+ it "should require the object to define sync_settings" do
16
+ expect { SyncTools::compare_json_file(AlmostValidClass.new) }.to raise_error(
17
+ SyncSettingsMissing
18
+ )
19
+ end
32
20
  end
33
21
 
34
- it "should require the object to define sync_settings" do
35
- i2_class = AlmostValidClass.new
36
- expect { SyncTools::compare_json_file(i2_class) }.to raise_error(
37
- SyncSettingsMissing
38
- )
22
+ context "compare_json_file" do
23
+ it "should return a change when one exists" do
24
+ artist = Artist.find(1)
25
+ changes = SyncTools::compare_json_file(artist)
26
+ changes.should be_an_instance_of(Array)
27
+ changes.length.should == 1
28
+ changes.first.should be_an_instance_of(Swim::Change)
29
+ end
30
+
31
+ it "should correctly identify changes" do
32
+ artist = Artist.find(2)
33
+ SyncTools.save_settings(artist)
34
+ artist.albums.first.title = "The Best of Billy Prestone"
35
+ changes = SyncTools::compare_json_file(artist)
36
+ changes.should be_an_instance_of(Array)
37
+ changes.length.should == 1
38
+ changes.first.should be_an_instance_of(Swim::Change)
39
+ end
39
40
  end
40
-
41
- it "should return a change when one exists" do
42
- artist = Artist.find(1)
43
- changes = SyncTools::compare_json_file(artist)
44
- changes.should be_an_instance_of(Array)
45
- changes.length.should == 1
46
- changes.first.should be_an_instance_of(Swim::Change)
47
- end
48
-
41
+
42
+ context "#save_settings" do
43
+ it "should save settings in a json file" do
44
+ artist = Artist.find(2)
45
+ expect { SyncTools.save_settings(artist) }
46
+ end
47
+
48
+ it "settings and object should be identical" do
49
+ artist = Artist.find(2)
50
+ SyncTools.save_settings(artist)
51
+ changes = SyncTools::compare_json_file(artist)
52
+ changes.should be_an_instance_of(Array)
53
+ changes.length.should == 0
54
+ end
55
+ end
56
+
49
57
  end
File without changes
@@ -0,0 +1 @@
1
+ {"artist":{"created_at":"2012-07-03T14:02:14-04:00","id":2,"name":"Billy Preston","updated_at":"2012-07-03T14:02:14-04:00","albums":[{"artist_id":2,"created_at":"2012-07-03T14:02:14-04:00","id":2,"title":"The Best of Billy Preston","updated_at":"2012-07-03T14:02:14-04:00"}]}}
File without changes
@@ -0,0 +1,9 @@
1
+ class AlmostValidClass
2
+ def settings_path
3
+ "#{__FILE__}/../../sample_files/almost_valid_class_settings.json"
4
+ end
5
+
6
+ # def self.sync_settings
7
+ # return Hash.new
8
+ # end
9
+ end
@@ -1,8 +1,8 @@
1
1
  class Artist < ActiveRecord::Base
2
2
  has_many :albums
3
3
 
4
- def settings_file
5
- File.expand_path("#{__FILE__}/../../sample_files/artist_settings.json")
4
+ def settings_path
5
+ "#{__FILE__}/../../sample_files/artist_#{id}_settings.json"
6
6
  end
7
7
 
8
8
  def self.sync_settings
@@ -0,0 +1,8 @@
1
+ class InvalidClass
2
+ # def self.settings_file
3
+ # return Hash.new
4
+ # end
5
+ # def self.sync_settings
6
+ # return Hash.new
7
+ # end
8
+ end
data/spec/spec_helper.rb CHANGED
File without changes
data/swim.gemspec CHANGED
@@ -6,9 +6,10 @@ Gem::Specification.new do |gem|
6
6
  gem.email = ["jerry@disruptiveventures.com"]
7
7
  gem.description = %q{Sync or Swim}
8
8
  gem.summary = %q{Synchronize ActiveRecord Objects Across Environments with JSON and git}
9
- gem.homepage = ""
9
+ gem.homepage = "http://disruptive.github.com/swim"
10
10
 
11
11
  gem.add_development_dependency 'rspec'
12
+ gem.add_development_dependency 'sqlite3'
12
13
  gem.files = `git ls-files`.split($\)
13
14
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
15
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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: 2012-07-03 00:00:00.000000000 Z
12
+ date: 2012-08-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  description: Sync or Swim
31
47
  email:
32
48
  - jerry@disruptiveventures.com
@@ -48,12 +64,15 @@ files:
48
64
  - spec/lib/swim_spec.rb
49
65
  - spec/lib/sync_tools_spec.rb
50
66
  - spec/sample_files/almost_valid_class_settings.json
51
- - spec/sample_files/artist_settings.json
67
+ - spec/sample_files/artist_1_settings.json
68
+ - spec/sample_files/artist_2_settings.json
52
69
  - spec/sample_models/album.rb
70
+ - spec/sample_models/almost_valid_class.rb
53
71
  - spec/sample_models/artist.rb
72
+ - spec/sample_models/invalid_class.rb
54
73
  - spec/spec_helper.rb
55
74
  - swim.gemspec
56
- homepage: ''
75
+ homepage: http://disruptive.github.com/swim
57
76
  licenses: []
58
77
  post_install_message:
59
78
  rdoc_options: []
@@ -65,15 +84,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
65
84
  - - ! '>='
66
85
  - !ruby/object:Gem::Version
67
86
  version: '0'
87
+ segments:
88
+ - 0
89
+ hash: 3293738542906190303
68
90
  required_rubygems_version: !ruby/object:Gem::Requirement
69
91
  none: false
70
92
  requirements:
71
93
  - - ! '>='
72
94
  - !ruby/object:Gem::Version
73
95
  version: '0'
96
+ segments:
97
+ - 0
98
+ hash: 3293738542906190303
74
99
  requirements: []
75
100
  rubyforge_project:
76
- rubygems_version: 1.8.23
101
+ rubygems_version: 1.8.24
77
102
  signing_key:
78
103
  specification_version: 3
79
104
  summary: Synchronize ActiveRecord Objects Across Environments with JSON and git
@@ -82,7 +107,10 @@ test_files:
82
107
  - spec/lib/swim_spec.rb
83
108
  - spec/lib/sync_tools_spec.rb
84
109
  - spec/sample_files/almost_valid_class_settings.json
85
- - spec/sample_files/artist_settings.json
110
+ - spec/sample_files/artist_1_settings.json
111
+ - spec/sample_files/artist_2_settings.json
86
112
  - spec/sample_models/album.rb
113
+ - spec/sample_models/almost_valid_class.rb
87
114
  - spec/sample_models/artist.rb
115
+ - spec/sample_models/invalid_class.rb
88
116
  - spec/spec_helper.rb