rubysync 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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