rubysync 0.0.1

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.
Files changed (161) hide show
  1. data/bin/rubysync +312 -0
  2. data/examples/ar_client_webapp/README +182 -0
  3. data/examples/ar_client_webapp/Rakefile +10 -0
  4. data/examples/ar_client_webapp/app/controllers/application.rb +7 -0
  5. data/examples/ar_client_webapp/app/controllers/user_controller.rb +5 -0
  6. data/examples/ar_client_webapp/app/helpers/application_helper.rb +3 -0
  7. data/examples/ar_client_webapp/app/helpers/user_helper.rb +2 -0
  8. data/examples/ar_client_webapp/app/models/user.rb +2 -0
  9. data/examples/ar_client_webapp/config/boot.rb +45 -0
  10. data/examples/ar_client_webapp/config/database.yml +36 -0
  11. data/examples/ar_client_webapp/config/environment.rb +60 -0
  12. data/examples/ar_client_webapp/config/environments/development.rb +21 -0
  13. data/examples/ar_client_webapp/config/environments/production.rb +18 -0
  14. data/examples/ar_client_webapp/config/environments/test.rb +19 -0
  15. data/examples/ar_client_webapp/config/routes.rb +23 -0
  16. data/examples/ar_client_webapp/db/migrate/001_create_users.rb +13 -0
  17. data/examples/ar_client_webapp/db/schema.rb +13 -0
  18. data/examples/ar_client_webapp/doc/README_FOR_APP +2 -0
  19. data/examples/ar_client_webapp/public/404.html +30 -0
  20. data/examples/ar_client_webapp/public/500.html +30 -0
  21. data/examples/ar_client_webapp/public/dispatch.cgi +10 -0
  22. data/examples/ar_client_webapp/public/dispatch.fcgi +24 -0
  23. data/examples/ar_client_webapp/public/dispatch.rb +10 -0
  24. data/examples/ar_client_webapp/public/favicon.ico +0 -0
  25. data/examples/ar_client_webapp/public/images/rails.png +0 -0
  26. data/examples/ar_client_webapp/public/index.html +277 -0
  27. data/examples/ar_client_webapp/public/javascripts/application.js +2 -0
  28. data/examples/ar_client_webapp/public/javascripts/controls.js +833 -0
  29. data/examples/ar_client_webapp/public/javascripts/dragdrop.js +942 -0
  30. data/examples/ar_client_webapp/public/javascripts/effects.js +1088 -0
  31. data/examples/ar_client_webapp/public/javascripts/prototype.js +2515 -0
  32. data/examples/ar_client_webapp/public/robots.txt +1 -0
  33. data/examples/ar_client_webapp/script/about +3 -0
  34. data/examples/ar_client_webapp/script/breakpointer +3 -0
  35. data/examples/ar_client_webapp/script/console +3 -0
  36. data/examples/ar_client_webapp/script/destroy +3 -0
  37. data/examples/ar_client_webapp/script/generate +3 -0
  38. data/examples/ar_client_webapp/script/performance/benchmarker +3 -0
  39. data/examples/ar_client_webapp/script/performance/profiler +3 -0
  40. data/examples/ar_client_webapp/script/plugin +3 -0
  41. data/examples/ar_client_webapp/script/process/inspector +3 -0
  42. data/examples/ar_client_webapp/script/process/reaper +3 -0
  43. data/examples/ar_client_webapp/script/process/spawner +3 -0
  44. data/examples/ar_client_webapp/script/runner +3 -0
  45. data/examples/ar_client_webapp/script/server +3 -0
  46. data/examples/ar_client_webapp/test/fixtures/users.yml +5 -0
  47. data/examples/ar_client_webapp/test/functional/user_controller_test.rb +18 -0
  48. data/examples/ar_client_webapp/test/test_helper.rb +28 -0
  49. data/examples/ar_client_webapp/test/unit/user_test.rb +10 -0
  50. data/examples/ar_webapp/README +1 -0
  51. data/examples/ar_webapp/Rakefile +10 -0
  52. data/examples/ar_webapp/app/controllers/application.rb +7 -0
  53. data/examples/ar_webapp/app/controllers/hobbies_controller.rb +10 -0
  54. data/examples/ar_webapp/app/controllers/interests_controller.rb +9 -0
  55. data/examples/ar_webapp/app/controllers/people_controller.rb +14 -0
  56. data/examples/ar_webapp/app/controllers/ruby_sync_associations_controller.rb +10 -0
  57. data/examples/ar_webapp/app/helpers/application_helper.rb +3 -0
  58. data/examples/ar_webapp/app/models/hobby.rb +5 -0
  59. data/examples/ar_webapp/app/models/interest.rb +6 -0
  60. data/examples/ar_webapp/app/models/person.rb +9 -0
  61. data/examples/ar_webapp/app/models/ruby_sync_association.rb +5 -0
  62. data/examples/ar_webapp/app/models/ruby_sync_event.rb +9 -0
  63. data/examples/ar_webapp/app/models/ruby_sync_observer.rb +28 -0
  64. data/examples/ar_webapp/app/models/ruby_sync_operation.rb +20 -0
  65. data/examples/ar_webapp/app/models/ruby_sync_state.rb +2 -0
  66. data/examples/ar_webapp/app/models/ruby_sync_value.rb +7 -0
  67. data/examples/ar_webapp/app/views/layouts/application.rhtml +19 -0
  68. data/examples/ar_webapp/app/views/people/show.rhtml +18 -0
  69. data/examples/ar_webapp/config/boot.rb +45 -0
  70. data/examples/ar_webapp/config/database.yml +36 -0
  71. data/examples/ar_webapp/config/environment.rb +61 -0
  72. data/examples/ar_webapp/config/environments/development.rb +21 -0
  73. data/examples/ar_webapp/config/environments/production.rb +18 -0
  74. data/examples/ar_webapp/config/environments/test.rb +19 -0
  75. data/examples/ar_webapp/config/routes.rb +23 -0
  76. data/examples/ar_webapp/db/migrate/001_create_people.rb +12 -0
  77. data/examples/ar_webapp/db/migrate/002_create_interests.rb +12 -0
  78. data/examples/ar_webapp/db/migrate/003_create_hobbies.rb +11 -0
  79. data/examples/ar_webapp/db/migrate/004_create_ruby_sync_associations.rb +18 -0
  80. data/examples/ar_webapp/db/migrate/005_create_ruby_sync_events.rb +16 -0
  81. data/examples/ar_webapp/db/migrate/006_create_ruby_sync_operations.rb +15 -0
  82. data/examples/ar_webapp/db/migrate/007_create_ruby_sync_values.rb +12 -0
  83. data/examples/ar_webapp/db/migrate/008_ruby_sync_tracking.rb +16 -0
  84. data/examples/ar_webapp/db/migrate/009_create_ruby_sync_states.rb +10 -0
  85. data/examples/ar_webapp/db/schema.rb +56 -0
  86. data/examples/ar_webapp/doc/README_FOR_APP +2 -0
  87. data/examples/ar_webapp/public/404.html +30 -0
  88. data/examples/ar_webapp/public/500.html +30 -0
  89. data/examples/ar_webapp/public/dispatch.cgi +10 -0
  90. data/examples/ar_webapp/public/dispatch.fcgi +24 -0
  91. data/examples/ar_webapp/public/dispatch.rb +10 -0
  92. data/examples/ar_webapp/public/favicon.ico +0 -0
  93. data/examples/ar_webapp/public/images/rails.png +0 -0
  94. data/examples/ar_webapp/public/index.html +277 -0
  95. data/examples/ar_webapp/public/javascripts/application.js +2 -0
  96. data/examples/ar_webapp/public/javascripts/controls.js +833 -0
  97. data/examples/ar_webapp/public/javascripts/dragdrop.js +942 -0
  98. data/examples/ar_webapp/public/javascripts/effects.js +1088 -0
  99. data/examples/ar_webapp/public/javascripts/prototype.js +2515 -0
  100. data/examples/ar_webapp/public/robots.txt +1 -0
  101. data/examples/ar_webapp/script/about +3 -0
  102. data/examples/ar_webapp/script/breakpointer +3 -0
  103. data/examples/ar_webapp/script/console +3 -0
  104. data/examples/ar_webapp/script/destroy +3 -0
  105. data/examples/ar_webapp/script/generate +3 -0
  106. data/examples/ar_webapp/script/performance/benchmarker +3 -0
  107. data/examples/ar_webapp/script/performance/profiler +3 -0
  108. data/examples/ar_webapp/script/plugin +3 -0
  109. data/examples/ar_webapp/script/process/inspector +3 -0
  110. data/examples/ar_webapp/script/process/reaper +3 -0
  111. data/examples/ar_webapp/script/process/spawner +3 -0
  112. data/examples/ar_webapp/script/runner +3 -0
  113. data/examples/ar_webapp/script/server +3 -0
  114. data/examples/ar_webapp/test/fixtures/association_keys.yml +5 -0
  115. data/examples/ar_webapp/test/fixtures/hobbies.yml +5 -0
  116. data/examples/ar_webapp/test/fixtures/interests.yml +5 -0
  117. data/examples/ar_webapp/test/fixtures/people.yml +9 -0
  118. data/examples/ar_webapp/test/fixtures/ruby_sync_events.yml +5 -0
  119. data/examples/ar_webapp/test/fixtures/ruby_sync_operations.yml +5 -0
  120. data/examples/ar_webapp/test/fixtures/ruby_sync_states.yml +5 -0
  121. data/examples/ar_webapp/test/fixtures/ruby_sync_values.yml +5 -0
  122. data/examples/ar_webapp/test/test_helper.rb +28 -0
  123. data/examples/ar_webapp/test/unit/association_key_test.rb +8 -0
  124. data/examples/ar_webapp/test/unit/hobby_test.rb +10 -0
  125. data/examples/ar_webapp/test/unit/interest_test.rb +10 -0
  126. data/examples/ar_webapp/test/unit/person_test.rb +10 -0
  127. data/examples/ar_webapp/test/unit/ruby_sync_event_test.rb +12 -0
  128. data/examples/ar_webapp/test/unit/ruby_sync_observer_test.rb +57 -0
  129. data/examples/ar_webapp/test/unit/ruby_sync_operation_test.rb +10 -0
  130. data/examples/ar_webapp/test/unit/ruby_sync_state_test.rb +10 -0
  131. data/examples/ar_webapp/test/unit/ruby_sync_value_test.rb +10 -0
  132. data/examples/ims2/connectors/hr_db_connector.rb +8 -0
  133. data/examples/ims2/connectors/my_csv_connector.rb +12 -0
  134. data/examples/ims2/pipelines/hr_import_pipeline.rb +33 -0
  135. data/examples/my_ims/connectors/corp_directory_connector.rb +12 -0
  136. data/examples/my_ims/connectors/finance_connector.rb +7 -0
  137. data/examples/my_ims/connectors/hr_db_connector.rb +7 -0
  138. data/examples/my_ims/pipelines/finance_pipeline.rb +33 -0
  139. data/examples/my_ims/pipelines/hr_import_pipeline.rb +29 -0
  140. data/lib/ruby_sync/connectors/active_record_connector.rb +198 -0
  141. data/lib/ruby_sync/connectors/base_connector.rb +317 -0
  142. data/lib/ruby_sync/connectors/connector_event_processing.rb +78 -0
  143. data/lib/ruby_sync/connectors/csv_file_connector.rb +95 -0
  144. data/lib/ruby_sync/connectors/file_connector.rb +74 -0
  145. data/lib/ruby_sync/connectors/ldap_connector.rb +192 -0
  146. data/lib/ruby_sync/connectors/memory_connector.rb +185 -0
  147. data/lib/ruby_sync/event.rb +220 -0
  148. data/lib/ruby_sync/operation.rb +82 -0
  149. data/lib/ruby_sync/pipelines/base_pipeline.rb +360 -0
  150. data/lib/ruby_sync/util/metaid.rb +24 -0
  151. data/lib/ruby_sync/util/utilities.rb +115 -0
  152. data/lib/ruby_sync.rb +81 -0
  153. data/test/hashlike_tests.rb +111 -0
  154. data/test/ruby_sync_test.rb +48 -0
  155. data/test/test_active_record_vault.rb +113 -0
  156. data/test/test_csv_file_connector.rb +75 -0
  157. data/test/test_event.rb +40 -0
  158. data/test/test_ldap_connector.rb +89 -0
  159. data/test/test_memory_connectors.rb +40 -0
  160. data/test/ts_rubysync.rb +20 -0
  161. metadata +316 -0
@@ -0,0 +1 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/about'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/breakpointer'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/console'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/destroy'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/generate'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/performance/benchmarker'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/performance/profiler'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/plugin'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/process/inspector'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/process/reaper'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../config/boot'
3
+ require 'commands/process/spawner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/runner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+ require 'commands/server'
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,9 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ bob:
3
+ id: 1
4
+ first_name: Bob
5
+ last_name: Roberts
6
+ sean:
7
+ id: 2
8
+ first_name: Sean
9
+ last_name: Connery
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ one:
3
+ id: 1
4
+ two:
5
+ id: 2
@@ -0,0 +1,28 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+
5
+ class Test::Unit::TestCase
6
+ # Transactional fixtures accelerate your tests by wrapping each test method
7
+ # in a transaction that's rolled back on completion. This ensures that the
8
+ # test database remains unchanged so your fixtures don't have to be reloaded
9
+ # between every test method. Fewer database queries means faster tests.
10
+ #
11
+ # Read Mike Clark's excellent walkthrough at
12
+ # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
13
+ #
14
+ # Every Active Record database supports transactions except MyISAM tables
15
+ # in MySQL. Turn off transactional fixtures in this case; however, if you
16
+ # don't care one way or the other, switching from MyISAM to InnoDB tables
17
+ # is recommended.
18
+ self.use_transactional_fixtures = true
19
+
20
+ # Instantiated fixtures are slow, but give you @david where otherwise you
21
+ # would need people(:david). If you don't want to migrate your existing
22
+ # test cases which use the @david style and don't mind the speed hit (each
23
+ # instantiated fixtures translates to a database query per test method),
24
+ # then set this back to true.
25
+ self.use_instantiated_fixtures = false
26
+
27
+ # Add more helper methods to be used by all tests here...
28
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RubySyncAssociationTest < Test::Unit::TestCase
4
+ fixtures :ruby_sync_associations
5
+
6
+ # Replace this with your real tests.
7
+
8
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class HobbyTest < Test::Unit::TestCase
4
+ fixtures :hobbies
5
+
6
+ # Replace this with your real tests.
7
+ def test_truth
8
+ assert true
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class InterestTest < Test::Unit::TestCase
4
+ fixtures :interests
5
+
6
+ # Replace this with your real tests.
7
+ def test_truth
8
+ assert true
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class PersonTest < Test::Unit::TestCase
4
+ fixtures :people
5
+
6
+ # Replace this with your real tests.
7
+ def test_truth
8
+ assert true
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RubySyncEventTest < Test::Unit::TestCase
4
+ fixtures :ruby_sync_events
5
+
6
+ # Replace this with your real tests.
7
+ def test_event_type
8
+ assert_nil RubySyncEvent.find_by_event_type(:add), "Already add events"
9
+ event = RubySyncEvent.create :event_type=>:add
10
+ assert_not_nil event = RubySyncEvent.find_by_event_type(:add), "Add event not created"
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RubySyncObserverTest < Test::Unit::TestCase
4
+ fixtures :people
5
+
6
+ def test_destroy
7
+ assert_nil RubySyncEvent.find_by_event_type('delete'), "Delete events already present"
8
+ Person.destroy people('bob')
9
+ event = RubySyncEvent.find_by_event_type 'delete'
10
+ assert_not_nil event, "Delete event not created on destroy"
11
+ assert_equal people('bob').id, event.trackable_id
12
+ assert_equal 'Person', event.trackable_type
13
+ end
14
+
15
+
16
+ def test_add
17
+ assert_nil RubySyncEvent.find_by_event_type('add'), "Add events already present"
18
+ p = Person.create(:first_name=>"Ritchie", :last_name=>"Young")
19
+ event = RubySyncEvent.find_by_event_type 'add'
20
+ assert_not_nil event, "Add event not created on create"
21
+ assert_equal p.id, event.trackable_id
22
+ assert_equal 'Person', event.trackable_type
23
+ # Ensure the fields were populated correctly
24
+ fn = event.operations.find_by_operation_and_field_name 'add', 'first_name'
25
+ assert_not_nil fn, "No add first_name operation"
26
+ assert_equal 1, fn.values.length
27
+ assert_equal "Ritchie", fn.values[0].value
28
+ fn = event.operations.find_by_operation_and_field_name 'add', 'last_name'
29
+ assert_not_nil fn, "No add last_name operation"
30
+ assert_equal 1, fn.values.length
31
+ assert_equal "Young", fn.values[0].value
32
+ #TODO: Add support for multi-value fields (AKA has_many associations)
33
+ end
34
+
35
+
36
+ def test_modify
37
+ assert_nil RubySyncEvent.find_by_event_type('modify'), "Modify events already present"
38
+ p = Person.find people('bob').id
39
+ assert_not_nil p, "Couldn't find bob"
40
+ p.first_name = "Mary"
41
+ p.save
42
+ event = RubySyncEvent.find_by_event_type 'modify'
43
+ assert_not_nil event, "Modify event not created on save"
44
+ assert_equal people('bob').id, event.trackable_id
45
+ assert_equal 'Person', event.trackable_type
46
+ # Ensure the fields were populated correctly
47
+ fn = event.operations.find_by_operation_and_field_name 'replace', 'first_name'
48
+ assert_not_nil fn, "No replace first_name operation"
49
+ assert_equal 1, fn.values.length
50
+ assert_equal "Mary", fn.values[0].value
51
+ #TODO: Add support for multi-value fields (AKA has_many associations)
52
+ end
53
+
54
+
55
+
56
+
57
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RubySyncOperationTest < Test::Unit::TestCase
4
+ fixtures :ruby_sync_operations
5
+
6
+ # Replace this with your real tests.
7
+ def test_truth
8
+ assert true
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RubySyncStateTest < Test::Unit::TestCase
4
+ fixtures :ruby_sync_states
5
+
6
+ # Replace this with your real tests.
7
+ def test_truth
8
+ assert true
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RubySyncValueTest < Test::Unit::TestCase
4
+ fixtures :ruby_sync_values
5
+
6
+ # Replace this with your real tests.
7
+ def test_truth
8
+ assert true
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ class HrDbConnector < RubySync::Connectors::ActiveRecordConnector
2
+ options(
3
+ :name=>"HR Database",
4
+ :application=>"#{File.dirname(__FILE__)}/../../ar_webapp",
5
+ :model=>:person
6
+ )
7
+
8
+ end
@@ -0,0 +1,12 @@
1
+ class MyCsvConnector < RubySync::Connectors::CsvFileConnector
2
+ options(
3
+ :name=>"MyCSV",
4
+ :field_names=>['given name', 'last name', 'phone number', 'email'],
5
+ :path_field=>'email',
6
+ :in_path=>'/tmp/csv/in',
7
+ :out_path=>'/tmp/csv/out',
8
+ :in_glob=>'*.csv',
9
+ :out_extension=>'.csv'
10
+ )
11
+
12
+ end
@@ -0,0 +1,33 @@
1
+ class HrImportPipeline < RubySync::Pipelines::BasePipeline
2
+
3
+ client :my_csv
4
+
5
+ vault :hr_db
6
+
7
+ # Remove any fields that you don't want to set in the client from the vault
8
+ allow_out :first_name, :last_name
9
+
10
+ # Remove any fields that you don't want to set in the vault from the client
11
+ allow_in :first_name, :last_name
12
+
13
+ # If the client and vault have different names for the same field, define the
14
+ # the mapping here. For example, if the vault has a field called "first name" and
15
+ # the client has a field called givenName you may put:
16
+ # 'first name' => 'givenName'
17
+ # separate each mapping with a comma.
18
+ # The following fields were detected on the client:
19
+ # 'given name', 'last name', 'phone number', 'email'
20
+ map_vault_to_client(
21
+ 'first_name' => 'given name',
22
+ 'last_name' => 'last name'
23
+ )
24
+
25
+ # "in" means going from client to vault
26
+ #in_transform do
27
+ #end
28
+
29
+ # "out" means going from vault to client
30
+ #out_transform do
31
+ #end
32
+
33
+ end
@@ -0,0 +1,12 @@
1
+ class CorpDirectoryConnector < RubySync::Connectors::LdapConnector
2
+
3
+ options(
4
+ :host=>'localhost',
5
+ :port=>10389,
6
+ :username=>'uid=admin,ou=system',
7
+ :password=>'secret',
8
+ :search_filter=>"cn=*",
9
+ :search_base=>"dc=example,dc=com"
10
+ )
11
+
12
+ end
@@ -0,0 +1,7 @@
1
+ class FinanceConnector < RubySync::Connectors::ActiveRecordConnector
2
+ options(
3
+ :application => "#{File.dirname(__FILE__)}/../../ar_client_webapp",
4
+ :model => :user
5
+ )
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ class HrDbConnector < RubySync::Connectors::ActiveRecordConnector
2
+
3
+ options(
4
+ :application => "#{File.dirname(__FILE__)}/../../ar_webapp",
5
+ :model => :person
6
+ )
7
+ end
@@ -0,0 +1,33 @@
1
+ class FinancePipeline < RubySync::Pipelines::BasePipeline
2
+
3
+ client :finance
4
+
5
+ vault :hr_db
6
+
7
+ # Remove any fields that you don't want to set in the client from the vault
8
+ allow_out :first_name
9
+
10
+ # Remove any fields that you don't want to set in the vault from the client
11
+ allow_in :first_name, :last_name
12
+
13
+ # If the client and vault have different names for the same field, define the
14
+ # the mapping here. For example, if the vault has a field called "first name" and
15
+ # the client has a field called givenName you may put:
16
+ # 'first name' => 'givenName'
17
+ # separate each mapping with a comma.
18
+ # The following fields were detected on the client:
19
+ # 'username', 'name', 'email'
20
+ map_vault_to_client(
21
+ 'first_name' => 'name'
22
+ #'last_name' => 'a_client_field'
23
+ )
24
+
25
+ # in means going from client to vault
26
+ #in_transform do
27
+ #end
28
+
29
+ # out means going from vault to client
30
+ #out_transform do
31
+ #end
32
+
33
+ end
@@ -0,0 +1,29 @@
1
+ class HrImportPipeline < RubySync::Pipelines::BasePipeline
2
+
3
+ client :corp_directory
4
+ vault :hr_db
5
+
6
+ map_client_to_vault :givenname => :first_name,
7
+ :sn => :last_name
8
+
9
+
10
+
11
+ allow_out :first_name, :last_name
12
+ allow_in :first_name, :last_name
13
+
14
+
15
+ # in means going from client to vault
16
+ #in_transform do
17
+ #end
18
+
19
+ # out means going from vault to client
20
+ out_transform do
21
+ add_default :cn, "Ritchie"
22
+ end
23
+
24
+ def out_place event
25
+ #event.target_path = "blah"
26
+ event.target_path = "cn=Ritchie,dc=example,dc=com"
27
+ end
28
+
29
+ end
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
4
+ #
5
+ # This file is part of RubySync.
6
+ #
7
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9
+ #
10
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
11
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
14
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15
+
16
+ require 'erb'
17
+ $VERBOSE=false
18
+ require "active_record"
19
+ #$VERBOSE=true
20
+ require "ruby_sync/connectors/base_connector"
21
+
22
+
23
+ module RubySync::Connectors
24
+
25
+ # You can initialize this connector with the name of a model and the path to a rails application:
26
+ # eg: vault :ActiveRecord, :application=>'path/to/rails/application', :model=>:user
27
+ class ActiveRecordConnector < RubySync::Connectors::BaseConnector
28
+
29
+
30
+ attr_accessor :ar_class, :model, :application, :rails_env, :db_type, :db_host, :db_name
31
+
32
+ def initialize options={}
33
+ super options
34
+ @rails_env ||= 'development'
35
+ @db_type ||= 'mysql'
36
+ @db_host ||= 'localhost'
37
+ @db_name ||= "rubysync_#{@rails_env}"
38
+ # Default db_config in case we're not sucking the config out of a rails app
39
+ @db_config = {
40
+ :adapter=>@db_type,
41
+ :host=>@db_host,
42
+ :database=>@db_name
43
+ }
44
+
45
+ # Rails app specified, use it to configure
46
+ if defined? @application
47
+ # Load the database configuration
48
+ rails_app_path = File.expand_path(@application, File.dirname(__FILE__))
49
+ db_config_filename = File.join(rails_app_path, 'config', 'database.yml')
50
+ @db_config = YAML::load(ERB.new(IO.read(db_config_filename)).result)[@rails_env]
51
+ # Require the models
52
+ log.debug "Loading the models for #{self.class.name}:"
53
+ Dir.chdir(File.join(rails_app_path,'app','models')) do
54
+ Dir.glob('*.rb') do |filename|
55
+ log.debug("\t#{filename}")
56
+ require filename
57
+ class_name = filename[0..-4].camelize
58
+ klass = class_name.constantize
59
+ klass.establish_connection @db_config if defined? klass.establish_connection
60
+ end
61
+ end
62
+ end
63
+
64
+ @model ||= :user
65
+ @ar_class ||= @model.to_s.camelize.constantize
66
+ end
67
+
68
+
69
+ def self.fields
70
+ c = self.new
71
+ c.ar_class.content_columns.map {|col| col.name }
72
+ end
73
+
74
+ def self.sample_config
75
+ return <<END
76
+ options(
77
+ #:application=>'/path/to/a/rails/application',
78
+ #:model=>'name_of_model_to_sync'
79
+ )
80
+ END
81
+ end
82
+
83
+
84
+ # Process each RubySyncEvent and then delete it from the db.
85
+ def check
86
+ ::RubySyncEvent.find(:all).each do |rse|
87
+ event = RubySync::Event.new(rse.event_type, self, rse.trackable_id, nil, to_payload(rse))
88
+ yield event
89
+ ::RubySyncEvent.delete rse
90
+ end
91
+ end
92
+
93
+ # Create a hash suitable to use as rubysync event payload
94
+ def to_payload ar_event
95
+ ar_event.operations.map do |op|
96
+ RubySync::Operation.new(op.operation.to_sym, op.field_name, op.values.map {|v| v.value})
97
+ end
98
+ end
99
+
100
+ # Override default perform_add because ActiveRecord is different in that
101
+ # the target path is ignored when adding a record. ActiveRecord determines
102
+ # the id on creation.
103
+ def perform_add event
104
+ log.info "Adding '#{event.target_path}' to '#{name}'"
105
+ @ar_class.new() do |record|
106
+ populate(record, perform_operations(event.payload))
107
+ log.info(record.inspect)
108
+ record.save!
109
+ if is_vault?
110
+ associate event.association, record.id
111
+ end
112
+ record.id
113
+ end
114
+ rescue => ex
115
+ log.warn ex
116
+ #puts ex.backtrace.join("\n")
117
+ return nil
118
+ end
119
+
120
+
121
+ def modify(path, operations)
122
+ @ar_class.find(path) do |record|
123
+ populate(record, perform_operations(operations))
124
+ record.save
125
+ end
126
+ end
127
+
128
+ def delete(path)
129
+ @ar_class.destroy path
130
+ end
131
+
132
+ # Implement vault functionality
133
+
134
+ def associate association, path
135
+ log.debug "Associating '#{association}' with '#{path}'"
136
+ ruby_sync_association.create :synchronizable_id=>path, :synchronizable_type=>@ar_class.name,
137
+ :context=>association.context, :key=>association.key
138
+ end
139
+
140
+ def find_associated association
141
+ ruby_sync_association.find_by_context_and_key association.context, association.key
142
+ end
143
+
144
+ def path_for_association association
145
+ assoc = ruby_sync_association.find_by_context_and_key association.context, association.key
146
+ (assoc)? assoc.synchronizable_id : nil
147
+ end
148
+
149
+ def association_key_for context, path
150
+ record = ruby_sync_association.find_by_synchronizable_id_and_synchronizable_type_and_context path, @model.to_s, context
151
+ record and record.key
152
+ end
153
+
154
+ def associations_for(path)
155
+ ruby_sync_association.find_by_synchronizable_id_and_synchronizable_type(path, @model.to_s)
156
+ rescue ActiveRecord::RecordNotFound
157
+ return nil
158
+ end
159
+
160
+ def remove_association association
161
+ ruby_sync_association.find_by_context_and_key(association.context, association.key).destroy
162
+ rescue ActiveRecord::RecordNotFound
163
+ return nil
164
+ end
165
+
166
+
167
+ def [](path)
168
+ @ar_class.find(path)
169
+ rescue ActiveRecord::RecordNotFound
170
+ return nil
171
+ end
172
+
173
+ private
174
+
175
+ def ruby_sync_association
176
+ unless @ruby_sync_association
177
+ @ruby_sync_association = ::RubySyncAssociation
178
+ ::RubySyncAssociation.establish_connection(@db_config)
179
+ end
180
+ @ruby_sync_association
181
+ end
182
+
183
+ def populate record, content
184
+ @ar_class.content_columns.each do |c|
185
+ record[c.name] = content[c.name][0] if content[c.name]
186
+ end
187
+ end
188
+
189
+ def create_operations_for_active_record record
190
+ operations = record.class.content_columns.map do |col|
191
+ key = col.name
192
+ value = record.send key
193
+ RubySync::Operation.new(:add, key.to_s, value) if key and value
194
+ end
195
+ operations.compact
196
+ end
197
+ end
198
+ end