swim 0.0.1 → 0.0.2

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/.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