ruby-macrodroid 0.8.4 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -54,16 +54,30 @@ class MacroObject
54
54
  @h[:siguid]
55
55
  end
56
56
 
57
- def to_s(colour: false)
58
-
57
+ def to_s(colour: false, indent: 0)
58
+
59
59
  h = @h.clone
60
60
  h.delete :macro
61
61
  @s ||= "#<%s %s>" % [self.class, h.inspect]
62
62
  operator = @h[:is_or_condition] ? 'OR' : 'AND'
63
63
  constraints = @constraints.map \
64
- {|x| x.to_summary(colour: colour)}.join(" %s " % operator)
64
+ {|x| 'c: ' + x.to_summary(colour: colour)}
65
+
66
+ out = []
67
+ out << "; %s" % @h[:comment] if @h[:comment] and @h[:comment].length > 1
68
+ #s = @s.lines.map {|x| 'x' + x}.join
69
+
70
+ lines = @s.lines
71
+
72
+ if lines.length > 1 then
73
+ s = lines[0] + lines[1..-1].map {|x| x.prepend (' ' * (indent+1)) }.join
74
+ else
75
+ s = @s
76
+ end
65
77
 
66
- @s + constraints
78
+ out << s
79
+ out += constraints
80
+ out.join("\n")
67
81
 
68
82
  end
69
83
 
@@ -0,0 +1,514 @@
1
+ # file: ruby-macrodroid/macro.rb
2
+
3
+
4
+ # This file contains the following classes:
5
+ #
6
+ # ## Macro class
7
+ #
8
+ # Macro
9
+
10
+ class Macro
11
+ using ColouredText
12
+ using Params
13
+
14
+ attr_reader :local_variables, :triggers, :actions, :constraints,
15
+ :guid, :deviceid
16
+ attr_accessor :title, :description
17
+
18
+ def initialize(name=nil, geofences: nil, deviceid: nil, debug: false)
19
+
20
+ @title, @geofences, @deviceid, @debug = name, geofences, deviceid, debug
21
+
22
+ puts 'inside Macro#initialize' if @debug
23
+
24
+ @local_variables, @triggers, @actions, @constraints = [], [], [], []
25
+ @h = {}
26
+
27
+ end
28
+
29
+ def add(obj)
30
+
31
+ if obj.kind_of? Trigger then
32
+
33
+ puts 'trigger found' if @debug
34
+ @triggers << obj
35
+
36
+ elsif obj.kind_of? Action
37
+
38
+ puts 'action found' if @debug
39
+ @actions << obj
40
+
41
+ elsif obj.kind_of? Constraint
42
+
43
+ puts 'constraint found' if @debug
44
+ @constraints << obj
45
+
46
+ end
47
+
48
+ end
49
+
50
+ def to_h()
51
+
52
+ h = {
53
+ local_variables: @local_variables,
54
+ m_trigger_list: @triggers.map(&:to_h),
55
+ m_action_list: @actions.map(&:to_h),
56
+ m_category: @category,
57
+ m_constraint_list: @constraints.map(&:to_h),
58
+ m_description: '',
59
+ m_name: title(),
60
+ m_excludeLog: false,
61
+ m_GUID: guid(),
62
+ m_isOrCondition: false,
63
+ m_enabled: false,
64
+ m_descriptionOpen: false,
65
+ m_headingColor: 0
66
+ }
67
+
68
+ puts 'h: ' + h.inspect if @debug
69
+
70
+ @h.merge(h)
71
+ end
72
+
73
+ def import_h(h)
74
+
75
+ if @debug then
76
+ puts 'inside import_h'
77
+ puts 'h:' + h.inspect
78
+ end
79
+
80
+ @category = h[:category]
81
+ @title = h[:name]
82
+ @description = h[:description]
83
+
84
+ # fetch the local variables
85
+ if h[:local_variables].any? and h[:local_variables].first.any? then
86
+
87
+ @local_variables = h[:local_variables].map do |var|
88
+
89
+ val = case var[:type]
90
+ when 0 # boolean
91
+ var[:boolean_value]
92
+ when 1 # integer
93
+ var[:int_value]
94
+ when 2 # string
95
+ var[:string_value]
96
+ when 3 # decimal
97
+ var[:decimal_Value]
98
+ end
99
+
100
+ [var[:name], val]
101
+
102
+ end.to_h
103
+ end
104
+
105
+ # fetch the triggers
106
+ @triggers = h[:trigger_list].map do |trigger|
107
+ puts 'trigger: ' + trigger.inspect
108
+ #exit
109
+ object(trigger.to_snake_case)
110
+
111
+ end
112
+
113
+ @actions = h[:action_list].map do |action|
114
+ object(action.to_snake_case)
115
+ end
116
+ puts 'before fetch constraints' if @debug
117
+ # fetch the constraints
118
+ @constraints = h[:constraint_list].map do |constraint|
119
+ object(constraint.to_snake_case)
120
+ end
121
+ puts 'after fetch constraints' if @debug
122
+ @h = h
123
+
124
+ %i(local_variables m_trigger_list m_action_list m_constraint_list)\
125
+ .each {|x| @h[x] = [] }
126
+ puts 'after @h set' if @debug
127
+ @h
128
+
129
+ end
130
+
131
+ def import_xml(node)
132
+
133
+ if @debug then
134
+ puts 'inside Macro#import_xml'
135
+ puts 'node: ' + node.xml.inspect
136
+ end
137
+
138
+ if node.element('triggers') then
139
+
140
+ # level 2
141
+
142
+ @title = node.attributes[:name]
143
+ @category = node.attributes[:category]
144
+ @description = node.attributes[:description]
145
+
146
+
147
+ # get all the triggers
148
+ @triggers = node.xpath('triggers/*').map do |e|
149
+
150
+ puts 'e.name: ' + e.name.inspect if @debug
151
+ {timer: TimerTrigger}[e.name.to_sym].new(e.attributes.to_h)
152
+
153
+ end
154
+
155
+ # get all the actions
156
+ @actions = node.xpath('actions/*').map do |e|
157
+
158
+ if e.name == 'notification' then
159
+
160
+ case e.attributes[:type].to_sym
161
+ when :popup
162
+ e.attributes.delete :type
163
+ ToastAction.new e.attributes.to_h
164
+ end
165
+
166
+ end
167
+
168
+ end
169
+
170
+ # get all the constraints
171
+ @constraints = node.xpath('constraints/*').map do |e|
172
+
173
+ puts 'e.name: ' + e.name.inspect if @debug
174
+ {airplanemode: AirplaneModeConstraint}[e.name.to_sym].new(e.attributes.to_h)
175
+
176
+ end
177
+
178
+ else
179
+
180
+ # Level 1
181
+
182
+ puts 'import_xml: inside level 1' if @debug
183
+
184
+ @title = node.text('macro') || node.attributes[:name]
185
+
186
+ #@description = node.attributes[:description]
187
+
188
+ tp = TriggersNlp.new
189
+
190
+ @triggers = node.xpath('trigger').map do |e|
191
+
192
+ r = tp.find_trigger e.text
193
+
194
+ puts 'found trigger ' + r.inspect if @debug
195
+
196
+ if r then
197
+ if r[0] == GeofenceTrigger then
198
+ GeofenceTrigger.new(r[1], geofences: @geofences)
199
+ else
200
+ r[0].new(r[1])
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ ap = ActionsNlp.new
207
+
208
+ @actions = node.xpath('action').flat_map do |e|
209
+
210
+ puts 'action e: ' + e.xml.inspect if @debug
211
+ puts 'e.text ' + e.text if @debug
212
+
213
+ item = e.element('item')
214
+ if item then
215
+
216
+ if item.element('description') then
217
+
218
+ item.xpath('description').map do |description|
219
+
220
+ inner_lines = description.text.to_s.strip.lines
221
+ puts 'inner_lines: ' + inner_lines.inspect if @debug
222
+
223
+ action = if e.text.to_s.strip.empty? then
224
+ inner_lines.shift.strip
225
+ else
226
+ e.text.strip
227
+ end
228
+
229
+ r = ap.find_action action
230
+ r[0].new(description) if r
231
+
232
+ end
233
+
234
+ else
235
+
236
+ action = e.text.strip
237
+ r = ap.find_action action
238
+
239
+ a = e.xpath('item/*')
240
+
241
+ h = if a.any? then
242
+ a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
243
+ else
244
+ {}
245
+ end
246
+
247
+ r = ap.find_action action
248
+ r[0].new(h) if r
249
+
250
+ end
251
+
252
+ else
253
+
254
+ action = e.text.strip
255
+ r = ap.find_action action
256
+ r[0].new(r[1]) if r
257
+
258
+ end
259
+
260
+ end
261
+
262
+ cp = ConstraintsNlp.new
263
+
264
+ @constraints = node.xpath('constraint').map do |e|
265
+
266
+ r = cp.find_constraint e.text
267
+ puts 'found constraint ' + r.inspect if @debug
268
+
269
+ if r then
270
+ r[0].new(r[1])
271
+ end
272
+
273
+ end
274
+
275
+ end
276
+
277
+ self
278
+
279
+ end
280
+
281
+ def match?(triggerx, detail={time: $env[:time]}, model=nil )
282
+
283
+ if @triggers.any? {|x| x.type == triggerx and x.match?(detail, model) } then
284
+
285
+ if @debug then
286
+ puts 'checking constraints ...'
287
+ puts '@constraints: ' + @constraints.inspect
288
+ end
289
+
290
+ if @constraints.all? {|x| x.match?($env.merge(detail), model) } then
291
+
292
+ true
293
+
294
+ else
295
+
296
+ return false
297
+
298
+ end
299
+
300
+ end
301
+
302
+ end
303
+
304
+ # invokes the actions
305
+ #
306
+ def run()
307
+ @actions.map(&:invoke)
308
+ end
309
+
310
+ # prepares the environment in order for triggers to test fire successfully
311
+ # Used for testing
312
+ #
313
+ def set_env()
314
+ @triggers.each(&:set_env)
315
+ end
316
+
317
+ def to_pc()
318
+
319
+ heading = '# ' + @title
320
+ heading += '\n# ' + @description if @description
321
+ condition = @triggers.first.to_pc
322
+ actions = @actions.map(&:to_pc).join("\n")
323
+
324
+ <<EOF
325
+ #{heading}
326
+
327
+ if #{condition} then
328
+ #{actions}
329
+ end
330
+ EOF
331
+ end
332
+
333
+ def to_s(colour: false)
334
+
335
+ indent = 0 #@actions.map(&:to_s).join.lines.length > 0 ? 1 : 0
336
+
337
+ a = []
338
+ a << '# ' + @category + "\n" if @category
339
+ a << (colour ? "m".bg_cyan.gray.bold : 'm') + ': ' + @title
340
+
341
+
342
+ if @description and @description.length >= 1 then
343
+ a << (colour ? "d".bg_gray.gray.bold : 'd') + ': ' \
344
+ + @description.gsub(/\n/,"\n ")
345
+ end
346
+
347
+ if @local_variables.length >= 1 then
348
+
349
+ vars = @local_variables.map do |k,v|
350
+ label = colour ? 'v'.bg_magenta : 'v'
351
+ label += ': '
352
+ label + "%s: %s" % [k,v]
353
+ end
354
+
355
+ a << vars.join("\n")
356
+ end
357
+
358
+ a << @triggers.map do |x|
359
+ s =-x.to_s(colour: colour)
360
+
361
+ s2 = if s.lines.length > 1 then
362
+ "\n" + s.lines.map {|x| x.prepend (' ' * (indent+1)) }.join
363
+ else
364
+ ' ' + s
365
+ end
366
+ #s.lines > 1 ? "\n" + x : x
367
+ (colour ? "t".bg_red.gray.bold : 't') + ":" + s2
368
+ end.join("\n")
369
+
370
+ actions = @actions.map do |x|
371
+
372
+
373
+ s = x.to_s(colour: colour)
374
+ #puts 's: ' + s.inspect
375
+
376
+
377
+
378
+ r = if indent <= 0 then
379
+
380
+ lines = s.lines
381
+
382
+ if lines.length > 1 then
383
+ s = lines.map {|x| x.prepend (' ' * (indent+1)) }.join
384
+ end
385
+
386
+ s2 = s.lines.length > 1 ? "\n" + s : ' ' + s
387
+
388
+ if colour then
389
+ "a".bg_blue.gray.bold + ":" + s2
390
+ else
391
+ "a:" + s2
392
+ end
393
+
394
+ elsif indent > 0
395
+
396
+ if s =~ /^Else/ then
397
+ (' ' * (indent-1)) + "%s" % s
398
+ elsif s =~ /^End/
399
+ indent -= 1
400
+ (' ' * indent) + "%s" % s
401
+ else
402
+ s2 = s.lines[0] + s.lines[1..-1].map {|x| (' ' * indent) + x }.join
403
+ (' ' * indent) + "%s" % s2
404
+ end
405
+
406
+ end
407
+
408
+ if s =~ /^(?:If|DO \/ WHILE)/i then
409
+
410
+ if indent < 1 then
411
+
412
+ r = if colour then
413
+ "a".bg_blue.gray.bold + ":\n %s" % s
414
+ else
415
+ "a:\n %s" % s
416
+ end
417
+
418
+ indent += 1
419
+ else
420
+ r = (' ' * indent) + "%s" % s
421
+ end
422
+
423
+ indent += 1
424
+ end
425
+
426
+ r
427
+
428
+ end.join("\n")
429
+
430
+
431
+
432
+
433
+ a << actions
434
+
435
+
436
+ if @constraints.any? then
437
+ a << @constraints.map do |x|
438
+ (colour ? "c".bg_green.gray.bold : 'c') + ": %s" % x
439
+ end.join("\n")
440
+ end
441
+
442
+
443
+
444
+
445
+
446
+ a.join("\n") + "\n"
447
+
448
+ end
449
+
450
+ def to_summary(colour: false)
451
+
452
+ if colour then
453
+
454
+ a = [
455
+ 'm'.bg_cyan.gray.bold + ': ' + @title,
456
+ 't'.bg_red.gray.bold + ': ' + @triggers.map \
457
+ {|x| x.to_summary(colour: false)}.join(", "),
458
+ 'a'.bg_blue.gray.bold + ': ' + @actions.map \
459
+ {|x| x.to_summary(colour: false)}.join(", ")
460
+ ]
461
+
462
+ if @constraints.any? then
463
+ a << 'c'.bg_green.gray.bold + ': ' + @constraints.map \
464
+ {|x| x.to_summary(colour: false)}.join(", ")
465
+ end
466
+
467
+ else
468
+
469
+ a = [
470
+ 'm: ' + @title,
471
+ 't: ' + @triggers.map {|x| x.to_summary(colour: false)}.join(", "),
472
+ 'a: ' + @actions.map {|x| x.to_summary(colour: false)}.join(", ")
473
+ ]
474
+
475
+ if @constraints.any? then
476
+ a << 'c: ' + @constraints.map \
477
+ {|x| x.to_summary(colour: false)}.join(", ")
478
+ end
479
+ end
480
+
481
+
482
+
483
+ a.join("\n") + "\n"
484
+
485
+ end
486
+
487
+ private
488
+
489
+ def guid()
490
+ '-' + rand(1..9).to_s + 18.times.map { rand 9 }.join
491
+ end
492
+
493
+ def object(h={})
494
+
495
+ puts ('inside object h:' + h.inspect).debug if @debug
496
+ klass = Object.const_get h[:class_type]
497
+ puts klass.inspect.highlight if $debug
498
+
499
+ if klass == GeofenceTrigger then
500
+ puts 'GeofenceTrigger found'.highlight if $debug
501
+ GeofenceTrigger.new(h, geofences: @geofences)
502
+ else
503
+ puts 'before klass'
504
+ h2 = h.merge( macro: self)
505
+ puts 'h2: ' + h2.inspect
506
+ r = klass.new h2
507
+ puts 'r:' + r.inspect
508
+ r
509
+
510
+ end
511
+
512
+ end
513
+
514
+ end