rubysync 0.1.1 → 0.2.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.
@@ -27,7 +27,7 @@ module RubySync
27
27
  self.new(:add, subject, values)
28
28
  end
29
29
 
30
- def self.delete subject, values
30
+ def self.delete subject, values=nil
31
31
  self.new(:delete, subject, values)
32
32
  end
33
33
 
@@ -58,11 +58,11 @@ module RubySync
58
58
 
59
59
  remove_method :values=
60
60
  def values=(values)
61
- @values = as_array(values)
61
+ @values = (values == nil)? nil : as_array(values)
62
62
  end
63
63
 
64
64
  def value
65
- @values[0]
65
+ @values and @values[0]
66
66
  end
67
67
 
68
68
  def value= new_value
@@ -40,12 +40,11 @@ module RubySync
40
40
  class BasePipeline
41
41
 
42
42
  include RubySync::Utilities
43
+ meta_eval {include(RubySync::Utilities)}
43
44
 
45
+ #add_dump_options
44
46
  attr_accessor :delay # delay in seconds between checking connectors
45
47
 
46
- array_option :dump_before, :dump_after
47
- dump_before []
48
- dump_after []
49
48
 
50
49
  def initialize
51
50
  @delay = 5
@@ -56,30 +55,47 @@ module RubySync
56
55
  end
57
56
 
58
57
  def self.client(connector_name, options={})
59
- class_name = RubySync::Connectors::BaseConnector.class_name_for(connector_name)
58
+ options = HashWithIndifferentAccess.new(options)
59
+ connector_class = class_called(connector_name, "connector")
60
+ unless connector_class
61
+ log.error "No connector called #connector_name}"
62
+ return
63
+ end
60
64
  options[:name] ||= "#{self.name}(client)"
61
65
  options[:is_vault] = false
62
66
  class_def 'client' do
63
- @client ||= eval(class_name).new(options)
67
+ @client ||= connector_class.new(options)
64
68
  end
65
69
  end
66
70
 
67
71
  def self.vault(connector_name, options={})
68
- class_name = RubySync::Connectors::BaseConnector.class_name_for(connector_name)
72
+ options = HashWithIndifferentAccess.new(options)
73
+ connector_class = class_called(connector_name, "connector")
74
+ unless connector_class
75
+ log.error "No connector called #{connector_name}"
76
+ return
77
+ end
69
78
  options[:name] ||= "#{self.name}(vault)"
70
79
  options[:is_vault] = true
71
80
  class_def 'vault' do
72
81
  unless @vault
73
- @vault = eval(class_name).new(options)
82
+ @vault = connector_class.new(options)
74
83
  @vault.pipeline = self
75
84
  end
76
85
  @vault
77
86
  end
78
87
  end
79
88
 
89
+ array_option :dump_before, :dump_after
90
+ dump_before HashWithIndifferentAccess.new
91
+ dump_after HashWithIndifferentAccess.new
80
92
 
81
- def self.in_transform(&blk) event_method :in_transform,&blk; end
82
- def self.out_transform(&blk) event_method :out_transform,&blk; end
93
+ def self.in_transform(&blk) deprecated_event_method :in_transform, :in_event_transform, &blk; end
94
+ def self.in_event_transform(&blk) event_method :in_event_transform,&blk; end
95
+ def self.in_command_transform(&blk) event_method :in_command_transform,&blk; end
96
+ def self.out_transform(&blk) deprecated_event_method :out_transform, :out_event_transform, &blk; end
97
+ def self.out_event_transform(&blk) event_method :out_event_transform,&blk; end
98
+ def self.out_command_transform(&blk) event_method :out_command_transform,&blk; end
83
99
  def self.in_match(&blk) event_method :in_match,&blk; end
84
100
  def self.out_match(&blk) event_method :out_match,&blk; end
85
101
  def self.in_create(&blk) event_method :in_create,&blk; end
@@ -89,14 +105,28 @@ module RubySync
89
105
 
90
106
  def self.event_method name,&blk
91
107
  define_method name do |event|
92
- event.instance_eval &blk
108
+ event.instance_eval(&blk)
93
109
  end
94
110
  end
95
111
 
112
+ def self.deprecated_event_method name, replacement, &blk
113
+ log.warn "'#{name}' has been deprecated. Use '#{replacement}' instead."
114
+ event_method(replacement, &blk)
115
+ end
116
+
117
+
96
118
  def in_match(event)
97
119
  log.debug "Default matching rule - vault[in_place] exists?"
98
- path = in_place(event)
99
- vault.respond_to?('[]') and vault[path] and path
120
+ if vault.respond_to?('[]')
121
+ path = in_place(event)
122
+ if path
123
+ log.debug "Checking for object at '#{path}' on vault."
124
+ vault[path] and path
125
+ end
126
+ else
127
+ log.debug "Vault doesn't support random access - no match"
128
+ nil
129
+ end
100
130
  end
101
131
 
102
132
  def out_match(event)
@@ -128,19 +158,10 @@ module RubySync
128
158
  def out_place_transform(event)
129
159
  event.target_path = out_place(event)
130
160
  end
131
-
132
- def perform_transform name, event, hint=""
133
- log.info "Performing #{name}"
134
- log.info event.to_yaml if dump_before.include?(name.to_sym)
135
- call_if_exists name, event, hint
136
- event.commit_changes
137
- log.info event.to_yaml if dump_after.include?(name.to_sym)
138
- #log_progress name, event, hint
139
- end
140
161
 
141
- # Execute the pipeline once then return.
162
+ # execute the pipeline once then return.
142
163
  def run_once
143
- log.info "Running #{name} pipeline once"
164
+ log.info "running #{name} pipeline once"
144
165
  started
145
166
  run_in_once
146
167
  run_out_once
@@ -157,26 +178,26 @@ module RubySync
157
178
  vault.stopped
158
179
  end
159
180
 
160
- # Execute the in pipe once and then return
181
+ # execute the in pipe once and then return
161
182
  def run_in_once
162
183
  return unless allowed_in
163
- log.debug "Running #{name} 'in' pipeline once"
184
+ log.debug "running #{name} 'in' pipeline once"
164
185
  client.once_only = true
165
186
  client.start {|event| in_handler(event)}
166
187
  end
167
188
 
168
- # Execute the out pipe once and then return
189
+ # execute the out pipe once and then return
169
190
  def run_out_once
170
191
  return unless allowed_out
171
- log.debug "Running #{name} 'out' pipeline once"
192
+ log.debug "running #{name} 'out' pipeline once"
172
193
  vault.once_only = true
173
194
  vault.start {|event| out_handler(event)}
174
195
  end
175
196
 
176
197
  def start
177
- log.info "Starting #{name} pipeline"
198
+ log.info "starting #{name} pipeline"
178
199
  @running = true
179
- trap("SIGINT") {self.stop}
200
+ trap("sigint") {self.stop}
180
201
  started
181
202
  while @running
182
203
  run_in_once
@@ -208,6 +229,8 @@ module RubySync
208
229
  log.info "Processing incoming #{event.type} event "+event.hint
209
230
  perform_transform :in_filter, event, event.hint
210
231
 
232
+ perform_transform :in_event_transform, event, event.hint
233
+
211
234
  associated_entry = nil
212
235
  unless event.type == :disassociate
213
236
  associated_entry = vault.find_associated(event.association) if event.associated?
@@ -218,22 +241,22 @@ module RubySync
218
241
  event.association = Association.new(association_context, event.source_path)
219
242
  vault.associate event.association, match
220
243
  associated_entry = vault[match]
244
+ else
245
+ log.info "No match found for unassociated entry."
221
246
  end
222
247
  end
223
248
  end
224
-
249
+
225
250
  if associated_entry
226
251
  if event.type == :add
227
- log.info "Associated entry in vault for add event. Converting to modify"
228
- event.convert_to_modify
252
+ log.info "Associated entry in vault for add event. Converting to modify"
253
+ event.convert_to_modify associated_entry, allowed_in
229
254
  end
230
255
  elsif event.type == :modify
231
- log.info "No associated entry in vault for modify event. Converting to add"
232
- event.convert_to_add
256
+ log.info "No associated entry in vault for modify event. Converting to add"
257
+ event.convert_to_add
233
258
  end
234
259
 
235
- perform_transform :in_transform, event, event.hint
236
-
237
260
  case event.type
238
261
  when :add
239
262
  if in_create(event)
@@ -252,20 +275,25 @@ module RubySync
252
275
  end
253
276
  end
254
277
 
255
- with_rescue("#{vault.name}: Processing command") {vault.process(event)}
278
+ perform_transform :in_command_transform, event, event.hint
279
+
280
+ if event.effective_operation?
281
+ with_rescue("#{vault.name}: Processing command") {vault.process(event)}
282
+ else
283
+ log.info "No change."
284
+ end
256
285
  log.info "---\n"
257
286
 
258
287
  end
259
288
 
260
- # Called by the 'in' connector in the 'in' thread to process events generated by the client.
261
- # Note: The client can't really know whether the event is an add or a modify because it doesn't store
262
- # the association.
289
+ # Called by the 'vault' connector in the 'out' thread to process events generated by the vault.
263
290
  def out_handler(event)
264
291
  event.target = @client
265
292
  event.retrieve_association(association_context)
266
293
 
267
294
  log.info "Processing outgoing #{event.type} event "+ event.hint
268
295
  perform_transform :out_filter, event, event.hint
296
+ perform_transform :out_event_transform, event, event.hint
269
297
 
270
298
  associated_entry = nil
271
299
  unless event.type == :disassociate
@@ -283,16 +311,14 @@ module RubySync
283
311
 
284
312
  if associated_entry
285
313
  if event.type == :add
286
- log.info "Associated entry in client for add event. Converting to modify"
287
- event.convert_to_modify
314
+ log.info "Associated entry in client for add event. Converting to modify"
315
+ event.convert_to_modify(associated_entry,allowed_out)
288
316
  end
289
317
  elsif event.type == :modify
290
- log.info "No associated entry in client for modify event. Converting to add"
291
- event.convert_to_add
318
+ log.info "No associated entry in client for modify event. Converting to add"
319
+ event.convert_to_add
292
320
  end
293
321
 
294
- perform_transform :out_transform, event, event.hint
295
-
296
322
  case event.type
297
323
  when :add
298
324
  if out_create(event)
@@ -311,6 +337,8 @@ module RubySync
311
337
  end
312
338
  end
313
339
 
340
+ perform_transform :out_command_transform, event, event.hint
341
+
314
342
  with_rescue("#{client.name}: Processing command") {client.process(event)}
315
343
  log.info "---\n"
316
344
 
@@ -434,7 +462,7 @@ module RubySync
434
462
 
435
463
 
436
464
  def in_filter(event)
437
- allowed_in == [] or event.drop_all_but_changes_to(allowed_in || [])
465
+ allowed_in == [] or event.drop_all_but_changes_to(allowed_in || [])
438
466
  end
439
467
 
440
468
 
@@ -450,7 +478,7 @@ module RubySync
450
478
  def allowed_out; nil; end
451
479
 
452
480
  def out_filter(event)
453
- allowed_out == [] or event.drop_all_but_changes_to(allowed_out || [])
481
+ allowed_out == [] or event.drop_all_but_changes_to(allowed_out || [])
454
482
  end
455
483
 
456
484
 
@@ -24,15 +24,15 @@ require 'irb'
24
24
 
25
25
 
26
26
  module Kernel
27
- # Make the log method globally available
28
- def log
29
- unless defined? @@log
30
- @@log = Logger.new(STDOUT)
31
- #@@log.level = Logger::DEBUG
32
- @@log.datetime_format = "%H:%M:%S"
33
- end
34
- @@log
35
- end
27
+ # Make the log method globally available
28
+ def log
29
+ unless defined? @@log
30
+ @@log = Logger.new(STDOUT)
31
+ #@@log.level = Logger::DEBUG
32
+ @@log.datetime_format = "%H:%M:%S"
33
+ end
34
+ @@log
35
+ end
36
36
  end
37
37
 
38
38
  class Array
@@ -41,6 +41,7 @@ class Array
41
41
  end
42
42
  end
43
43
 
44
+
44
45
  # Generally useful methods
45
46
  module RubySync
46
47
  module Utilities
@@ -59,7 +60,20 @@ module RubySync
59
60
  log.warn "#{text}: #{exception.message}"
60
61
  log.debug exception.backtrace.join("\n")
61
62
  end
62
- end
63
+ end
64
+
65
+ def dump_before
66
+ []
67
+ end
68
+
69
+ def dump_after() []; end
70
+ def perform_transform name, event, hint=""
71
+ log.info event.to_yaml if dump_before.include?(name.to_sym)
72
+ log.info "performing #{name}"
73
+ call_if_exists name, event, hint
74
+ event.commit_changes
75
+ log.info event.to_yaml if dump_after.include?(name.to_sym)
76
+ end
63
77
 
64
78
  def call_if_exists(method, event, hint="")
65
79
  result = nil
@@ -92,19 +106,45 @@ module RubySync
92
106
  end
93
107
 
94
108
  def pipeline_called name
95
- something_called name, "pipeline"
109
+ begin
110
+ something_called name, "pipeline"
111
+ rescue
112
+ log.error "Pipeline named '#{name}' not found."
113
+ nil
114
+ end
96
115
  end
97
116
 
98
117
 
99
- def connector_called name
100
- something_called name, "connector"
118
+ def connector_called name, message=nil
119
+ begin
120
+ something_called name, "connector"
121
+ rescue
122
+ message ||= "Connector named '#{name}' not found."
123
+ log.error message
124
+ nil
125
+ end
101
126
  end
102
127
 
103
128
  # Locates and returns an instance of a class for
104
129
  # the given name.
105
- def something_called name, extension
106
- filename = "#{name.to_s}_#{extension}"
107
- eval(filename.camelize).new
130
+ def something_called name, extension, message=nil
131
+ klass = class_called(name, extension, message) and klass.new()
132
+ end
133
+
134
+ def class_called name, extension, message=nil
135
+ class_for_name(class_name_for(name, extension), message)
136
+ end
137
+
138
+ def class_for_name(name, message=nil)
139
+ eval(name)
140
+ rescue
141
+ message ||= "Unable to find class called '#{name}'"
142
+ log.error message
143
+ nil
144
+ end
145
+
146
+ def class_name_for name, extension
147
+ "#{name.to_s}_#{extension}".camelize
108
148
  end
109
149
 
110
150
  # Ensure that path is in the search path
@@ -130,7 +170,7 @@ module RubySync
130
170
  # Keep going up until we start repeating ourselves
131
171
  while File.directory?(bp) && bp != last && bp != "/"
132
172
  return bp if File.directory?("#{bp}/pipelines") &&
133
- File.directory?("#{bp}/connectors")
173
+ File.directory?("#{bp}/connectors")
134
174
  last = bp
135
175
  bp = File.expand_path("#{bp}/..")
136
176
  end
@@ -163,25 +203,28 @@ module RubySync
163
203
  log.warn "!!!!!!!!!! PROBLEM, DUMP FOLLOWS: !!!!!!!!!!!!!!"
164
204
  p op
165
205
  end
166
- next if subjects and !subjects.include?(op.subject)
206
+ key = op.subject
207
+ next if subjects and !subjects.include?(key)
167
208
  case op.type
168
209
  when :add
169
- if record[op.subject]
170
- existing = as_array(record[op.subject])
210
+ if record[key]
211
+ existing = as_array(record[key])
171
212
  next if existing == op.values # already same so ignore
172
213
  (existing & op.values).empty? or
173
- raise "Attempt to add duplicate elements to #{name}"
174
- record[op.subject] = existing + op.values
214
+ raise "Attempt to add duplicate elements to #{name}"
215
+ record[key] = existing + op.values
175
216
  else
176
- record[op.subject] = op.values
217
+ record[key] = op.values
177
218
  end
178
219
  when :replace
179
- record[op.subject] = op.values
220
+ record[key] = op.values
180
221
  when :delete
181
- if value == nil || value == "" || value == []
182
- record.delete(op.subject)
183
- else
184
- record[op.subject] -= values
222
+ if record[key]
223
+ unless op.value
224
+ record.delete(op.subject)
225
+ else
226
+ record[key] -= op.values
227
+ end
185
228
  end
186
229
  else
187
230
  raise Exception.new("Unknown operation '#{op.type}'")
@@ -214,7 +257,7 @@ module RubySync
214
257
  effective << op
215
258
  end
216
259
  when :delete
217
- if [nil, "", []].include?(op.values)
260
+ unless op.value
218
261
  effective << op if record[op.subject]
219
262
  else
220
263
  targets = op.values & existing