ruby-macrodroid 0.8.12 → 0.9.4
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ruby-macrodroid.rb +16 -330
- data/lib/ruby-macrodroid/actions.rb +224 -39
- data/lib/ruby-macrodroid/base.rb +109 -15
- data/lib/ruby-macrodroid/constraints.rb +24 -4
- data/lib/ruby-macrodroid/macro.rb +501 -68
- data/lib/ruby-macrodroid/triggers.rb +46 -14
- metadata +10 -10
- metadata.gz.sig +0 -0
data/lib/ruby-macrodroid/base.rb
CHANGED
@@ -7,7 +7,95 @@
|
|
7
7
|
# MacroObject
|
8
8
|
#
|
9
9
|
|
10
|
+
module ObjectX
|
11
|
+
|
12
|
+
def action_to_object(ap, e, item, macro)
|
13
|
+
|
14
|
+
debug = true
|
15
|
+
|
16
|
+
puts 'inside action_to_object: item.xml: ' + item.xml if debug
|
17
|
+
|
18
|
+
if item.element('description') then
|
19
|
+
|
20
|
+
item.xpath('description').map do |description|
|
21
|
+
|
22
|
+
inner_lines = description.text.to_s.strip.lines
|
23
|
+
puts 'inner_lines: ' + inner_lines.inspect if debug
|
24
|
+
|
25
|
+
action = if e.text.to_s.strip.empty? then
|
26
|
+
inner_lines.shift.strip
|
27
|
+
else
|
28
|
+
e.text.strip
|
29
|
+
end
|
30
|
+
|
31
|
+
puts 'action: ' + action.inspect if debug
|
32
|
+
|
33
|
+
r = ap.find_action action
|
34
|
+
puts 'r: ' + r.inspect if debug
|
35
|
+
puts 'description: ' + description.xml.inspect if debug
|
36
|
+
#o = r[0].new([description, self]) if r
|
37
|
+
index = macro.actions.length
|
38
|
+
macro.add Action.new
|
39
|
+
o = object_create(r[0],[description, macro]) if r
|
40
|
+
macro.actions[index] = o
|
41
|
+
puts 'after o' if debug
|
42
|
+
o
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
else
|
47
|
+
|
48
|
+
action = e.text.strip
|
49
|
+
puts 'action: ' + action.inspect if @debug
|
50
|
+
r = ap.find_action action
|
51
|
+
|
52
|
+
a = e.xpath('item/*')
|
53
|
+
|
54
|
+
h = if a.any? then
|
55
|
+
a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
|
56
|
+
else
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
puts 'h: ' + h.inspect if @debug
|
60
|
+
|
61
|
+
#r = ap.find_action action
|
62
|
+
#r[0].new(h.merge(macro: self)) if r
|
63
|
+
o = object_create(r[0], h.merge(macro: macro)) if r
|
64
|
+
macro.add o
|
65
|
+
o
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
10
71
|
|
72
|
+
def object_create(klass, *args)
|
73
|
+
|
74
|
+
begin
|
75
|
+
klass.new(*args)
|
76
|
+
rescue
|
77
|
+
raise MacroError, klass.to_s + ': ' + ($!).to_s
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def varify(label, value='')
|
82
|
+
|
83
|
+
type = VAR_TYPES[value.class.to_s.to_sym]
|
84
|
+
|
85
|
+
h = {
|
86
|
+
boolean_value: false,
|
87
|
+
decimal_value: 0.0,
|
88
|
+
int_value: 0,
|
89
|
+
name: label,
|
90
|
+
string_value: '',
|
91
|
+
type: type[0]
|
92
|
+
}
|
93
|
+
h[type[1]] = value
|
94
|
+
h
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
11
99
|
|
12
100
|
class MacroObject
|
13
101
|
using ColouredText
|
@@ -34,19 +122,7 @@ class MacroObject
|
|
34
122
|
|
35
123
|
def to_h()
|
36
124
|
|
37
|
-
|
38
|
-
|
39
|
-
h2 = h.inject({}) do |r,x|
|
40
|
-
puts 'x: ' + x.inspect if @debug
|
41
|
-
key, value = x
|
42
|
-
puts 'key: ' + key.inspect if @debug
|
43
|
-
new_key = key.to_s.gsub(/\w_\w/){|x| x[0] + x[-1].upcase}
|
44
|
-
new_key = new_key.prepend 'm_' unless @list.include? new_key
|
45
|
-
new_key = 'm_SIGUID' if new_key == 'm_siguid'
|
46
|
-
r.merge(new_key => value)
|
47
|
-
end
|
48
|
-
|
49
|
-
h2.merge('m_classType' => self.class.to_s)
|
125
|
+
hashify(@h)
|
50
126
|
|
51
127
|
end
|
52
128
|
|
@@ -98,13 +174,31 @@ class MacroObject
|
|
98
174
|
|
99
175
|
def object(h={})
|
100
176
|
|
101
|
-
puts ('inside object h:' + h.inspect).debug if
|
177
|
+
puts ('inside object h:' + h.inspect).debug if $debug
|
102
178
|
klass = Object.const_get h[:class_type]
|
103
179
|
puts klass.inspect.highlight if $debug
|
104
180
|
|
105
181
|
klass.new h
|
106
182
|
|
107
|
-
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def hashify(h)
|
188
|
+
|
189
|
+
h2 = h.inject({}) do |r,x|
|
190
|
+
puts 'x: ' + x.inspect if $debug
|
191
|
+
key, value = x
|
192
|
+
puts 'key: ' + key.inspect if $debug
|
193
|
+
new_key = key.to_s.gsub(/\w_\w/){|x| x[0] + x[-1].upcase}
|
194
|
+
new_key = new_key.prepend 'm_' unless @list.include? new_key
|
195
|
+
new_key = 'm_SIGUID' if new_key == 'm_siguid'
|
196
|
+
new_val = value.is_a?(Hash) ? hashify(value) : value
|
197
|
+
r.merge(new_key => new_val)
|
198
|
+
end
|
199
|
+
|
200
|
+
h2.merge('m_classType' => self.class.to_s)
|
201
|
+
end
|
108
202
|
|
109
203
|
end
|
110
204
|
|
@@ -794,6 +794,13 @@ class MacroDroidVariableConstraint < Constraint
|
|
794
794
|
|
795
795
|
def initialize(h={})
|
796
796
|
|
797
|
+
if h[:loperand] then
|
798
|
+
h[:variable] = {}
|
799
|
+
h[:variable][:name] = h[:loperand]
|
800
|
+
h[:variable][:type] = 2
|
801
|
+
h[:string_value] = h[:roperand]
|
802
|
+
end
|
803
|
+
|
797
804
|
options = {
|
798
805
|
|
799
806
|
:enable_regex=>false,
|
@@ -825,11 +832,24 @@ class MacroDroidVariableConstraint < Constraint
|
|
825
832
|
|
826
833
|
def to_s(colour: false, indent: 0)
|
827
834
|
|
828
|
-
|
829
|
-
|
830
|
-
|
835
|
+
a = [:int_greater_than, :int_less_than, :int_not_equal,
|
836
|
+
:string_equal].zip(['>','<','!=', '='])
|
837
|
+
operator = a.find {|label,_| @h[label]}.last
|
838
|
+
|
839
|
+
var = @h[:variable]
|
840
|
+
|
841
|
+
type = case var[:type]
|
842
|
+
when 0 # boolean
|
843
|
+
:boolean_value
|
844
|
+
when 1 # integer
|
845
|
+
:int_value
|
846
|
+
when 2 # string
|
847
|
+
:string_value
|
848
|
+
when 3 # decimal
|
849
|
+
:decimal_Value
|
850
|
+
end
|
831
851
|
|
832
|
-
@s = "%s %s %s" % [@h[:variable][:name], operator, @h[
|
852
|
+
@s = "%s %s %s" % [@h[:variable][:name], operator, @h[type]]
|
833
853
|
super()
|
834
854
|
end
|
835
855
|
|
@@ -3,6 +3,10 @@
|
|
3
3
|
|
4
4
|
# This file contains the following classes:
|
5
5
|
#
|
6
|
+
# ## Nlp classes
|
7
|
+
#
|
8
|
+
# TriggersNlp ActionsNlp ConstraintsNlp
|
9
|
+
#
|
6
10
|
# ## Macro class
|
7
11
|
#
|
8
12
|
# Macro
|
@@ -12,32 +16,414 @@
|
|
12
16
|
VAR_TYPES = {
|
13
17
|
String: [2, :string_value],
|
14
18
|
TrueClass: [0, :boolean_value],
|
15
|
-
|
19
|
+
FalseClass: [0, :boolean_value],
|
16
20
|
Integer: [1, :int_value],
|
17
21
|
Float: [3, :decimal_value]
|
18
22
|
}
|
19
23
|
|
20
24
|
|
25
|
+
|
26
|
+
class TriggersNlp
|
27
|
+
include AppRoutes
|
28
|
+
|
29
|
+
def initialize(macro=nil)
|
30
|
+
|
31
|
+
super()
|
32
|
+
params = {macro: macro}
|
33
|
+
triggers(params)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def triggers(params)
|
38
|
+
|
39
|
+
# e.g. at 7:30pm daily
|
40
|
+
get /^(?:at )?(\d+:\d+(?:[ap]m)?) daily/i do |time, days|
|
41
|
+
[TimerTrigger, {time: time,
|
42
|
+
days: %w(Mon Tue Wed Thu Fri Sat Sun).join(', ')}]
|
43
|
+
end
|
44
|
+
|
45
|
+
get /^(?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)/i do |time, days|
|
46
|
+
[TimerTrigger, {time: time, days: days}]
|
47
|
+
end
|
48
|
+
|
49
|
+
# time.is? 'at 18:30pm on Mon or Tue'
|
50
|
+
get /^time.is\? ['"](?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)['"]/i do |time, days|
|
51
|
+
[TimerTrigger, {time: time, days: days.gsub(' or ',', ')}]
|
52
|
+
end
|
53
|
+
|
54
|
+
get /^shake[ _]device\??$/i do
|
55
|
+
[ShakeDeviceTrigger, {}]
|
56
|
+
end
|
57
|
+
|
58
|
+
get /^Flip Device (.*)$/i do |motion|
|
59
|
+
facedown = motion =~ /Face Up (?:->|to) Face Down/i
|
60
|
+
[FlipDeviceTrigger, {face_down: facedown }]
|
61
|
+
end
|
62
|
+
|
63
|
+
get /^flip_device_down\?$/i do
|
64
|
+
[FlipDeviceTrigger, {face_down: true }]
|
65
|
+
end
|
66
|
+
|
67
|
+
get /^flip_device_up\?$/i do
|
68
|
+
[FlipDeviceTrigger, {face_down: false }]
|
69
|
+
end
|
70
|
+
|
71
|
+
get /^Failed Login Attempt$/i do
|
72
|
+
[FailedLoginTrigger, {}]
|
73
|
+
end
|
74
|
+
|
75
|
+
get /^failed_login?$/i do
|
76
|
+
[FailedLoginTrigger, {}]
|
77
|
+
end
|
78
|
+
|
79
|
+
get /^Geofence (Entry|Exit) \(([^\)]+)/i do |direction, name|
|
80
|
+
enter_area = direction.downcase.to_sym == :entry
|
81
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
82
|
+
end
|
83
|
+
|
84
|
+
get /^location (entered|exited) \(([^\)]+)/i do |direction, name|
|
85
|
+
enter_area = direction.downcase.to_sym == :entered
|
86
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
87
|
+
end
|
88
|
+
|
89
|
+
# eg. Proximity Sensor (Near)
|
90
|
+
#
|
91
|
+
get /^Proximity Sensor \(([^\)]+)\)/i do |distance|
|
92
|
+
|
93
|
+
[ProximityTrigger, {distance: distance}]
|
94
|
+
end
|
95
|
+
|
96
|
+
# eg. Proximity near
|
97
|
+
#
|
98
|
+
get /^Proximity (near|far|slow wave|fast wave)/i do |distance|
|
99
|
+
|
100
|
+
[ProximityTrigger, {distance: distance}]
|
101
|
+
end
|
102
|
+
|
103
|
+
get /^WebHook \(Url\)/i do
|
104
|
+
[WebHookTrigger, params]
|
105
|
+
end
|
106
|
+
|
107
|
+
get /^WebHook/i do
|
108
|
+
[WebHookTrigger, params]
|
109
|
+
end
|
110
|
+
|
111
|
+
get /^wh/i do
|
112
|
+
[WebHookTrigger, params]
|
113
|
+
end
|
114
|
+
|
115
|
+
# MacroDroid specific ---------------------------------------------------------------
|
116
|
+
|
117
|
+
get /^EmptyTrigger$/i do
|
118
|
+
[EmptyTrigger, params]
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
alias find_trigger run_route
|
124
|
+
|
125
|
+
def to_s(colour: false)
|
126
|
+
'TriggersNlp ' + @h.inspect
|
127
|
+
end
|
128
|
+
|
129
|
+
alias to_summary to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
class ActionsNlp
|
133
|
+
include AppRoutes
|
134
|
+
|
135
|
+
def initialize(macro=nil)
|
136
|
+
|
137
|
+
super()
|
138
|
+
params = {macro: macro}
|
139
|
+
actions(params)
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
def actions(params)
|
144
|
+
|
145
|
+
# e.g. message popup: hello world!
|
146
|
+
get /^message popup: (.*)/i do |msg|
|
147
|
+
[ToastAction, {msg: msg}]
|
148
|
+
end
|
149
|
+
|
150
|
+
# e.g. Popup Message 'hello world!'
|
151
|
+
get /^Popup[ _]Message ['"]([^'"]+)/i do |msg|
|
152
|
+
[ToastAction, {msg: msg}]
|
153
|
+
end
|
154
|
+
|
155
|
+
# e.g. Popup Message\n hello world!
|
156
|
+
get /^Popup Message\n\s+(.*)/im do |msg|
|
157
|
+
[ToastAction, {msg: msg}]
|
158
|
+
end
|
159
|
+
|
160
|
+
# e.g. Popup Message
|
161
|
+
get /^Popup Message$/i do
|
162
|
+
[ToastAction, {}]
|
163
|
+
end
|
164
|
+
|
165
|
+
# e.g. say current time
|
166
|
+
get /^say current[ _]time/i do
|
167
|
+
[SayTimeAction, {}]
|
168
|
+
end
|
169
|
+
|
170
|
+
get /^Torch :?(.*)/i do |onoffstate|
|
171
|
+
state = %w(on off toggle).index onoffstate.downcase
|
172
|
+
[CameraFlashLightAction, {state: state}]
|
173
|
+
end
|
174
|
+
|
175
|
+
get /^Take Picture/i do
|
176
|
+
[TakePictureAction, {}]
|
177
|
+
end
|
178
|
+
|
179
|
+
get /^take_picture/i do
|
180
|
+
[TakePictureAction, {}]
|
181
|
+
end
|
182
|
+
|
183
|
+
# -- DEVICE ACTIONS ------------------------------------------------------
|
184
|
+
|
185
|
+
get /^Speak text \(([^\)]+)\)/i do |text|
|
186
|
+
[SpeakTextAction, {text: text}]
|
187
|
+
end
|
188
|
+
|
189
|
+
get /^Speak text ['"]([^'"]+)/i do |text|
|
190
|
+
[SpeakTextAction, {text: text}]
|
191
|
+
end
|
192
|
+
|
193
|
+
get /^Speak text$/i do |text|
|
194
|
+
[SpeakTextAction, {}]
|
195
|
+
end
|
196
|
+
|
197
|
+
get /^Vibrate \(([^\)]+)/i do |pattern|
|
198
|
+
[VibrateAction, {pattern: pattern}]
|
199
|
+
end
|
200
|
+
|
201
|
+
# e.g. Display Notification: Hi there: This is the body of the message
|
202
|
+
get /^Display Notification: ([^:]+): [^$]+$/i do |subject, text|
|
203
|
+
[NotificationAction, {subject: subject, text: text}]
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
# e.g. Enable Wifi
|
208
|
+
get /^(Enable|Disable) Wifi$/i do |raw_state|
|
209
|
+
|
210
|
+
state = raw_state.downcase.to_sym == :enable ? 0 : 1
|
211
|
+
[SetWifiAction, {state: state}]
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
# e.g. Play: Altair
|
216
|
+
get /^Play: (.*)$/i do |name|
|
217
|
+
|
218
|
+
[PlaySoundAction, {file_path: name}]
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
# e.g. Launch Settings
|
223
|
+
get /^Launch (.*)$/i do |application|
|
224
|
+
|
225
|
+
h = {
|
226
|
+
application_name: application,
|
227
|
+
package_to_launch: 'com.android.' + application.downcase
|
228
|
+
}
|
229
|
+
[LaunchActivityAction, h]
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
# e.g. HTTP GET http://someurl.com/something
|
234
|
+
get /^HTTP GET ([^$]+)$/i do |url|
|
235
|
+
|
236
|
+
[OpenWebPageAction, url_to_open: url]
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
get /^HTTP GET$/i do
|
241
|
+
|
242
|
+
[OpenWebPageAction, {}]
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
# e.g. webhook entered_kitchen
|
247
|
+
#
|
248
|
+
get /(?:webhook|HTTP GET) ([^$]+)$/i do |s|
|
249
|
+
key = s =~ /^http/ ? :url_to_open : :identifier
|
250
|
+
[OpenWebPageAction, {key => s}]
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
get /^WebHook \(Url\)/i do
|
255
|
+
[OpenWebPageAction, params]
|
256
|
+
end
|
257
|
+
|
258
|
+
# e.g. webhook entered_kitchen
|
259
|
+
#
|
260
|
+
get /^webhook$/i do
|
261
|
+
[OpenWebPageAction, params]
|
262
|
+
end
|
263
|
+
|
264
|
+
# -- Location ---------------------------------------------------------
|
265
|
+
|
266
|
+
get /^Force Location Update$/i do
|
267
|
+
[ForceLocationUpdateAction, params]
|
268
|
+
end
|
269
|
+
|
270
|
+
get /^Share Location$/i do
|
271
|
+
[ShareLocationAction, params]
|
272
|
+
end
|
273
|
+
|
274
|
+
#a: Keep Device Awake Screen On Until Disabled
|
275
|
+
#
|
276
|
+
get /Keep Device Awake Screen On Until Disabled/i do
|
277
|
+
[KeepAwakeAction, {enabled: true, permanent: true, screen_option: 0}]
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
#a: Keep Device Awake Screen On 1h 1m 1s
|
282
|
+
#
|
283
|
+
get /Keep Device Awake Screen On ([^$]+)/i do |duration|
|
284
|
+
|
285
|
+
a = duration.split.map(&:to_i)
|
286
|
+
secs = Subunit.new(units={minutes:60, hours:60, seconds: 60}, a).to_i
|
287
|
+
|
288
|
+
h = {
|
289
|
+
permanent: true, screen_option: 0, seconds_to_stay_awake_for: secs
|
290
|
+
}
|
291
|
+
[KeepAwakeAction, h]
|
292
|
+
end
|
293
|
+
|
294
|
+
get /Keep Device Awake$/i do
|
295
|
+
[KeepAwakeAction, params]
|
296
|
+
end
|
297
|
+
|
298
|
+
#a: Disable Keep Awake
|
299
|
+
#
|
300
|
+
get /Disable Keep Awake/i do
|
301
|
+
[KeepAwakeAction, {enabled: false, screen_option: 0}]
|
302
|
+
end
|
303
|
+
|
304
|
+
#e.g a: if Airplane mode enabled
|
305
|
+
#
|
306
|
+
get /if (.*)/i do
|
307
|
+
[IfConditionAction, {}]
|
308
|
+
end
|
309
|
+
|
310
|
+
get /End If/i do
|
311
|
+
[EndIfAction, {}]
|
312
|
+
end
|
313
|
+
|
314
|
+
# -- MacroDroid Specific ------------------------------------------------
|
315
|
+
#
|
316
|
+
get /^Set Variable$/i do
|
317
|
+
[SetVariableAction, {}]
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
alias find_action run_route
|
323
|
+
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
class ConstraintsNlp
|
328
|
+
include AppRoutes
|
329
|
+
|
330
|
+
def initialize()
|
331
|
+
|
332
|
+
super()
|
333
|
+
params = {}
|
334
|
+
constraints(params)
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
def constraints(params)
|
339
|
+
|
340
|
+
# Device State
|
341
|
+
|
342
|
+
get /^Device (locked|unlocked)/i do |state|
|
343
|
+
[DeviceLockedConstraint, {locked: state.downcase == 'locked'}]
|
344
|
+
end
|
345
|
+
|
346
|
+
get /^airplane mode (.*)/i do |state|
|
347
|
+
[AirplaneModeConstraint, {enabled: (state =~ /^enabled|on$/i) == 0}]
|
348
|
+
end
|
349
|
+
|
350
|
+
#
|
351
|
+
|
352
|
+
# -- MacroDroid specific -----------------------------------------------------------------------
|
353
|
+
|
354
|
+
get /^(\w+) (=) (\[?\w+\]?)/i do |loperand, operator, roperand|
|
355
|
+
|
356
|
+
h = {
|
357
|
+
loperand: loperand,
|
358
|
+
operator: operator,
|
359
|
+
roperand: roperand
|
360
|
+
}
|
361
|
+
|
362
|
+
[MacroDroidVariableConstraint, h]
|
363
|
+
|
364
|
+
end
|
365
|
+
|
366
|
+
# -- Sensors -----------------------------------
|
367
|
+
#
|
368
|
+
get /^Light Sensor (Less|Greater) than (50.0)lx/i do |operator, val|
|
369
|
+
|
370
|
+
level, option = operator.downcase == 'less' ? [-1,0] : [1,1]
|
371
|
+
|
372
|
+
h = {
|
373
|
+
light_level: level,
|
374
|
+
light_level_float: val,
|
375
|
+
option: option
|
376
|
+
}
|
377
|
+
|
378
|
+
[LightLevelConstraint, h]
|
379
|
+
end
|
380
|
+
|
381
|
+
get /^Proximity Sensor: (Near|Far)/i do |distance|
|
382
|
+
[ProximitySensorConstraint, {near: distance.downcase == 'near'}]
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
# -- Screen and Speaker ---------------------------
|
387
|
+
#
|
388
|
+
get /^Screen (On|Off)/i do |state|
|
389
|
+
[ScreenOnOffConstraint, {screen_on: state.downcase == 'on'}]
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
|
394
|
+
alias find_constraint run_route
|
395
|
+
|
396
|
+
end
|
397
|
+
|
398
|
+
|
399
|
+
class MacroError < Exception
|
400
|
+
end
|
401
|
+
|
21
402
|
class Macro
|
22
403
|
using ColouredText
|
23
404
|
using Params
|
405
|
+
include ObjectX
|
24
406
|
|
25
407
|
attr_reader :local_variables, :triggers, :actions, :constraints,
|
26
408
|
:guid, :deviceid
|
27
|
-
attr_accessor :title, :description
|
409
|
+
attr_accessor :title, :description, :remote_url
|
28
410
|
|
29
|
-
def initialize(name=nil, geofences: nil, deviceid: nil,
|
411
|
+
def initialize(name=nil, geofences: nil, deviceid: nil, remote_url: nil,
|
412
|
+
debug: false)
|
30
413
|
|
31
414
|
@title, @geofences, @deviceid, @debug = name, geofences, deviceid, debug
|
415
|
+
@remote_url = remote_url
|
32
416
|
|
33
417
|
puts 'inside Macro#initialize' if @debug
|
34
418
|
|
35
|
-
@local_variables, @triggers, @actions, @constraints =
|
419
|
+
@local_variables, @triggers, @actions, @constraints = {}, [], [], []
|
36
420
|
@h = {}
|
37
421
|
|
38
422
|
end
|
39
423
|
|
40
424
|
def add(obj)
|
425
|
+
puts 'inside add; ' + obj.inspect
|
426
|
+
puts '@actions: ' + @actions.inspect
|
41
427
|
|
42
428
|
if obj.kind_of? Trigger then
|
43
429
|
|
@@ -59,9 +445,13 @@ class Macro
|
|
59
445
|
end
|
60
446
|
|
61
447
|
def to_h()
|
448
|
+
|
449
|
+
a = @local_variables.map do |k,v|
|
450
|
+
varify(k,v).to_camelcase.map{|key,value| ['m_' + key, value]}.to_h
|
451
|
+
end
|
62
452
|
|
63
453
|
h = {
|
64
|
-
local_variables:
|
454
|
+
local_variables: a,
|
65
455
|
m_trigger_list: @triggers.map(&:to_h),
|
66
456
|
m_action_list: @actions.map(&:to_h),
|
67
457
|
m_category: @category,
|
@@ -71,7 +461,7 @@ class Macro
|
|
71
461
|
m_excludeLog: false,
|
72
462
|
m_GUID: guid(),
|
73
463
|
m_isOrCondition: false,
|
74
|
-
m_enabled:
|
464
|
+
m_enabled: true,
|
75
465
|
m_descriptionOpen: false,
|
76
466
|
m_headingColor: 0
|
77
467
|
}
|
@@ -96,7 +486,7 @@ class Macro
|
|
96
486
|
if h[:local_variables].any? and h[:local_variables].first.any? then
|
97
487
|
|
98
488
|
@local_variables = h[:local_variables].map do |var|
|
99
|
-
|
489
|
+
|
100
490
|
val = case var[:type]
|
101
491
|
when 0 # boolean
|
102
492
|
var[:boolean_value]
|
@@ -115,7 +505,7 @@ class Macro
|
|
115
505
|
|
116
506
|
# fetch the triggers
|
117
507
|
@triggers = h[:trigger_list].map do |trigger|
|
118
|
-
puts 'trigger: ' + trigger.inspect
|
508
|
+
puts 'trigger: ' + trigger.inspect if @debug
|
119
509
|
#exit
|
120
510
|
object(trigger.to_snake_case)
|
121
511
|
|
@@ -194,37 +584,33 @@ class Macro
|
|
194
584
|
|
195
585
|
@title = node.text('macro') || node.attributes[:name]
|
196
586
|
|
197
|
-
|
198
|
-
|
587
|
+
d = node.element('description')
|
588
|
+
|
589
|
+
if d then
|
590
|
+
|
591
|
+
desc = []
|
592
|
+
desc << d.text.strip
|
593
|
+
|
594
|
+
if d.element('item/description') then
|
595
|
+
desc << d.text('item/description').strip
|
596
|
+
end
|
597
|
+
|
598
|
+
@description = desc.join("\n")
|
599
|
+
|
199
600
|
end
|
200
601
|
|
602
|
+
node.xpath('variable').each {|e| set_var(*e.text.to_s.split(/: */,2)) }
|
603
|
+
|
201
604
|
#@description = node.attributes[:description]
|
202
605
|
|
203
606
|
tp = TriggersNlp.new(self)
|
204
607
|
|
205
|
-
@triggers = node.xpath('trigger').
|
608
|
+
@triggers = node.xpath('trigger').flat_map do |e|
|
206
609
|
|
207
610
|
r = tp.find_trigger e.text
|
208
611
|
|
209
612
|
puts 'found trigger ' + r.inspect if @debug
|
210
613
|
|
211
|
-
if r then
|
212
|
-
if r[0] == GeofenceTrigger then
|
213
|
-
GeofenceTrigger.new(r[1], geofences: @geofences)
|
214
|
-
else
|
215
|
-
r[0].new(r[1])
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
end
|
220
|
-
|
221
|
-
ap = ActionsNlp.new
|
222
|
-
|
223
|
-
@actions = node.xpath('action').flat_map do |e|
|
224
|
-
|
225
|
-
puts 'action e: ' + e.xml.inspect if @debug
|
226
|
-
puts 'e.text ' + e.text if @debug
|
227
|
-
|
228
614
|
item = e.element('item')
|
229
615
|
if item then
|
230
616
|
|
@@ -235,26 +621,27 @@ class Macro
|
|
235
621
|
inner_lines = description.text.to_s.strip.lines
|
236
622
|
puts 'inner_lines: ' + inner_lines.inspect if @debug
|
237
623
|
|
238
|
-
|
624
|
+
trigger = if e.text.to_s.strip.empty? then
|
239
625
|
inner_lines.shift.strip
|
240
626
|
else
|
241
627
|
e.text.strip
|
242
628
|
end
|
243
629
|
|
244
|
-
puts '
|
630
|
+
puts 'trigger: ' + trigger.inspect if @debug
|
245
631
|
|
246
|
-
r =
|
632
|
+
r = tp.find_trigger trigger
|
247
633
|
puts 'r: ' + r.inspect if @debug
|
248
|
-
o = r[0].new(description) if r
|
249
|
-
|
634
|
+
#o = r[0].new([description, self]) if r
|
635
|
+
o = object_create(r[0], [description, self]) if r
|
636
|
+
puts 'after o' if @debug
|
250
637
|
o
|
251
638
|
|
252
639
|
end
|
253
640
|
|
254
641
|
else
|
255
642
|
|
256
|
-
|
257
|
-
r =
|
643
|
+
trigger = e.text.strip
|
644
|
+
r = tp.find_trigger trigger
|
258
645
|
|
259
646
|
a = e.xpath('item/*')
|
260
647
|
|
@@ -264,18 +651,56 @@ class Macro
|
|
264
651
|
{}
|
265
652
|
end
|
266
653
|
|
267
|
-
r =
|
268
|
-
r[0].new(h) if r
|
654
|
+
r = tp.find_trigger trigger
|
655
|
+
#r[0].new(h) if r
|
656
|
+
if r then
|
657
|
+
object_create(r[0], h)
|
658
|
+
else
|
659
|
+
raise MacroError, 'App-routes: Trigger "' + trigger + '" not found'
|
660
|
+
end
|
269
661
|
|
270
662
|
end
|
271
663
|
|
664
|
+
else
|
665
|
+
|
666
|
+
trigger = e.text.strip
|
667
|
+
r = tp.find_trigger trigger
|
668
|
+
#r[0].new(r[1]) if r
|
669
|
+
|
670
|
+
if r then
|
671
|
+
object_create(r[0],r[1])
|
672
|
+
else
|
673
|
+
raise MacroError, 'App-routes: Trigger "' + trigger + '" not found'
|
674
|
+
end
|
675
|
+
|
676
|
+
end
|
677
|
+
|
678
|
+
|
679
|
+
end
|
680
|
+
|
681
|
+
|
682
|
+
|
683
|
+
ap = ActionsNlp.new self
|
684
|
+
|
685
|
+
node.xpath('action').each do |e|
|
686
|
+
|
687
|
+
puts 'action e: ' + e.xml.inspect if @debug
|
688
|
+
puts 'e.text ' + e.text if @debug
|
689
|
+
|
690
|
+
item = e.element('item')
|
691
|
+
|
692
|
+
if item then
|
693
|
+
|
694
|
+
action_to_object(ap, e, item, self)
|
695
|
+
|
272
696
|
else
|
273
697
|
|
274
698
|
action = e.text.strip
|
275
699
|
r = ap.find_action action
|
276
|
-
r[0].new(r[1]) if r
|
700
|
+
#r[0].new(r[1]) if r
|
701
|
+
self.add object_create(r[0],r[1]) if r
|
277
702
|
|
278
|
-
end
|
703
|
+
end
|
279
704
|
|
280
705
|
end
|
281
706
|
|
@@ -286,9 +711,7 @@ class Macro
|
|
286
711
|
r = cp.find_constraint e.text
|
287
712
|
puts 'found constraint ' + r.inspect if @debug
|
288
713
|
|
289
|
-
if r
|
290
|
-
r[0].new(r[1])
|
291
|
-
end
|
714
|
+
object_create(r[0], r[1]) if r
|
292
715
|
|
293
716
|
end
|
294
717
|
|
@@ -333,6 +756,27 @@ class Macro
|
|
333
756
|
def set_env()
|
334
757
|
@triggers.each(&:set_env)
|
335
758
|
end
|
759
|
+
|
760
|
+
def set_var(label, v='')
|
761
|
+
|
762
|
+
value = if v.to_f.to_s == v
|
763
|
+
v.to_f
|
764
|
+
elsif v.downcase == 'true'
|
765
|
+
true
|
766
|
+
elsif v.downcase == 'false'
|
767
|
+
false
|
768
|
+
elsif v.to_i.to_s == v
|
769
|
+
v.to_i
|
770
|
+
else
|
771
|
+
v
|
772
|
+
end
|
773
|
+
|
774
|
+
if not @local_variables.has_key? label.to_sym then
|
775
|
+
@local_variables.merge!({label.to_sym => value})
|
776
|
+
end
|
777
|
+
|
778
|
+
varify(label, value)
|
779
|
+
end
|
336
780
|
|
337
781
|
def to_pc()
|
338
782
|
|
@@ -378,13 +822,21 @@ EOF
|
|
378
822
|
puts 'before triggers' if @debug
|
379
823
|
|
380
824
|
a << @triggers.map do |x|
|
825
|
+
|
826
|
+
puts 'x: ' + x.inspect if @debug
|
827
|
+
raise 'Macro#to_s trigger cannot be nil' if x.nil?
|
828
|
+
|
381
829
|
s =-x.to_s(colour: colour)
|
830
|
+
puts 's: ' + s.inspect if @debug
|
382
831
|
|
383
832
|
s2 = if s.lines.length > 1 then
|
384
833
|
"\n" + s.lines.map {|x| x.prepend (' ' * (indent+1)) }.join
|
385
834
|
else
|
386
835
|
' ' + s
|
387
836
|
end
|
837
|
+
|
838
|
+
puts 's2: ' + s2.inspect if @debug
|
839
|
+
|
388
840
|
#s.lines > 1 ? "\n" + x : x
|
389
841
|
(colour ? "t".bg_red.gray.bold : 't') + ":" + s2
|
390
842
|
end.join("\n")
|
@@ -519,43 +971,24 @@ EOF
|
|
519
971
|
|
520
972
|
puts ('inside object h:' + h.inspect).debug if @debug
|
521
973
|
klass = Object.const_get h[:class_type]
|
522
|
-
puts klass.inspect.highlight if
|
974
|
+
puts klass.inspect.highlight if @debug
|
523
975
|
|
524
976
|
if klass == GeofenceTrigger then
|
525
|
-
puts 'GeofenceTrigger found'.highlight if
|
977
|
+
puts 'GeofenceTrigger found'.highlight if @debug
|
526
978
|
GeofenceTrigger.new(h, geofences: @geofences)
|
527
979
|
else
|
528
|
-
puts 'before klass'
|
980
|
+
puts 'before klass' if @debug
|
529
981
|
h2 = h.merge( macro: self)
|
530
|
-
puts 'h2: ' + h2.inspect
|
982
|
+
puts 'h2: ' + h2.inspect if @debug
|
531
983
|
r = klass.new h2
|
532
|
-
puts 'r:' + r.inspect
|
984
|
+
puts 'r:' + r.inspect if @debug
|
533
985
|
r
|
534
986
|
|
535
987
|
end
|
536
988
|
|
537
989
|
end
|
538
990
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
local_variables.map do |key, value|
|
543
|
-
|
544
|
-
|
545
|
-
type = VAR_TYPES[value.class.to_s.to_sym]
|
546
|
-
|
547
|
-
h = {
|
548
|
-
boolean_value: false,
|
549
|
-
decimal_value: 0.0,
|
550
|
-
int_value: 0,
|
551
|
-
name: key,
|
552
|
-
string_value: '',
|
553
|
-
type: type[0]
|
554
|
-
}
|
555
|
-
h[type[1]] = value
|
556
|
-
h
|
557
|
-
end
|
558
|
-
|
559
|
-
end
|
991
|
+
|
992
|
+
|
560
993
|
|
561
994
|
end
|