ruby-macrodroid 0.8.4 → 0.8.10

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