qcmd 0.1.15 → 0.1.16.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/qcmd/actions/base_action.rb +72 -8
- data/lib/qcmd/actions/cue_action.rb +7 -2
- data/lib/qcmd/aliases.rb +3 -1
- data/lib/qcmd/commands.rb +22 -0
- data/lib/qcmd/version.rb +1 -1
- data/spec/unit/action_spec.rb +67 -0
- data/spec/unit/parser_spec.rb +5 -0
- metadata +10 -7
@@ -1,6 +1,7 @@
|
|
1
1
|
module Qcmd
|
2
2
|
class BaseAction
|
3
3
|
attr_reader :code
|
4
|
+
attr_accessor :modification
|
4
5
|
|
5
6
|
# initialize and evaluate in one shot
|
6
7
|
def self.evaluate action_input
|
@@ -24,7 +25,7 @@ module Qcmd
|
|
24
25
|
expression = Qcmd::Parser.parse(expression)
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
+
parse(expression)
|
28
29
|
end
|
29
30
|
|
30
31
|
def evaluate
|
@@ -32,7 +33,7 @@ module Qcmd
|
|
32
33
|
nil
|
33
34
|
else
|
34
35
|
@code = code.map do |token|
|
35
|
-
if token.is_a?(
|
36
|
+
if token.is_a?(BaseAction)
|
36
37
|
Qcmd.debug "[Action evaluate] evaluating nested action: #{ token.code.inspect }"
|
37
38
|
token.evaluate
|
38
39
|
else
|
@@ -42,17 +43,22 @@ module Qcmd
|
|
42
43
|
|
43
44
|
Qcmd.debug "[Action evaluate] evaluating code: #{ code.inspect }"
|
44
45
|
|
45
|
-
send_message
|
46
|
+
response = send_message
|
47
|
+
if modification
|
48
|
+
modification.call(response)
|
49
|
+
else
|
50
|
+
response
|
51
|
+
end
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
55
|
+
# convert nested arrays into new actions
|
49
56
|
def parse(expression)
|
50
|
-
# unwrap nested arrays
|
51
57
|
if expression.size == 1 && expression[0].is_a?(Array)
|
52
58
|
expression = expression[0]
|
53
59
|
end
|
54
60
|
|
55
|
-
expression.map do |token|
|
61
|
+
@code = expression.map do |token|
|
56
62
|
if token.is_a?(Array)
|
57
63
|
if [:cue, :cue_id].include?(token.first)
|
58
64
|
Qcmd.debug "nested cue action detected in #{ expression.inspect }"
|
@@ -66,6 +72,31 @@ module Qcmd
|
|
66
72
|
end.tap {|exp|
|
67
73
|
Qcmd.debug "[Action parse] returning: #{ exp.inspect }"
|
68
74
|
}
|
75
|
+
|
76
|
+
# if there's a trailing modifier command, replace it with an action that will
|
77
|
+
# return a value that can be modified.
|
78
|
+
if tm = trailing_modifier
|
79
|
+
Qcmd.debug "[Action parse] found trailing modifier: #{ tm.inspect }"
|
80
|
+
|
81
|
+
mod_type = tm[0]
|
82
|
+
mod_value = tm[2].to_f
|
83
|
+
|
84
|
+
# clone this action without the final arg
|
85
|
+
new_action = self.class.new(@code[0, @code.size - 1])
|
86
|
+
|
87
|
+
Qcmd.debug "[Action parse] creating modification proc: value.send(:#{ mod_type }, #{ mod_value })"
|
88
|
+
new_action.modification = Proc.new {|value|
|
89
|
+
Qcmd.debug "[Action parse] executing modification proc: #{ value }.send(:#{ mod_type }, #{ mod_value })"
|
90
|
+
if value.respond_to?(mod_type)
|
91
|
+
value.send mod_type, mod_value
|
92
|
+
else
|
93
|
+
Qcmd.log :warning, "The command `#{ new_action.code.join(' ') }` returned a value of type #{ value.class.to_s } which does not understand the #{ mod_type } modifier."
|
94
|
+
value
|
95
|
+
end
|
96
|
+
}
|
97
|
+
|
98
|
+
code[code.size - 1] = new_action
|
99
|
+
end
|
69
100
|
end
|
70
101
|
|
71
102
|
# the default command builder
|
@@ -97,14 +128,47 @@ module Qcmd
|
|
97
128
|
|
98
129
|
private
|
99
130
|
|
131
|
+
# is the last argument to the osc command a modifier?
|
132
|
+
# returns nil or [modifier, matcher, matched_value]
|
133
|
+
def trailing_modifier
|
134
|
+
if osc_arguments && !osc_arguments.last.is_a?(BaseAction)
|
135
|
+
modifier = modifiers.find {|(_, matcher)|
|
136
|
+
matcher =~ osc_arguments.last.to_s
|
137
|
+
}
|
138
|
+
|
139
|
+
if modifier
|
140
|
+
modifier + [$1]
|
141
|
+
else
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
else
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def number_matcher
|
150
|
+
# matches 1.9, .9, or 1
|
151
|
+
"(?: [0-9]+ \. [0-9]+ | \. [0-9]+ | [0-9]+ )"
|
152
|
+
end
|
153
|
+
|
154
|
+
def modifiers
|
155
|
+
[
|
156
|
+
[:+, /^\+\+(#{ number_matcher })/x],
|
157
|
+
[:-, /--(#{ number_matcher })/x],
|
158
|
+
[:/, /\/\/(#{ number_matcher })/x],
|
159
|
+
[:*, /\*\*(#{ number_matcher })/x]
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
163
|
+
def modifier_matchers
|
164
|
+
modifiers.map(&:last)
|
165
|
+
end
|
166
|
+
|
100
167
|
def send_message
|
101
168
|
responses = []
|
102
169
|
|
103
170
|
Qcmd.debug "[Action send_message] send #{ osc_message.encode }"
|
104
171
|
Qcmd.context.qlab.send(osc_message) do |response|
|
105
|
-
# puts "response to: #{ osc_message.inspect }"
|
106
|
-
# puts response.inspect
|
107
|
-
|
108
172
|
responses << QLab::Reply.new(response)
|
109
173
|
end
|
110
174
|
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module Qcmd
|
2
|
-
class CueAction <
|
3
|
-
# cue commands
|
2
|
+
class CueAction < BaseAction
|
3
|
+
# cue commands should be in the form:
|
4
|
+
#
|
5
|
+
# [$id_field, $identifier, $command[, $arguments]]
|
6
|
+
#
|
7
|
+
# where arguments are optional.
|
8
|
+
|
4
9
|
def command
|
5
10
|
code[2]
|
6
11
|
end
|
data/lib/qcmd/aliases.rb
CHANGED
@@ -3,7 +3,7 @@ module Qcmd
|
|
3
3
|
def self.defaults
|
4
4
|
@defaults ||= {
|
5
5
|
'n' => 'cue $1 name $2',
|
6
|
-
# zero-out cue_number
|
6
|
+
# zero-out sliders for cue_number
|
7
7
|
'zero-out' => '(log-silent)' +
|
8
8
|
(1..48).map {|n| "(cue $1 sliderLevel #{n} 0)"}.join(' ') +
|
9
9
|
'(log-noisy) (echo "set slider levels for cue $1 to all zeros")',
|
@@ -11,6 +11,8 @@ module Qcmd
|
|
11
11
|
'copy-sliders' => '(log-silent)' +
|
12
12
|
(1..48).map {|n| "(cue $2 sliderLevel #{n} (cue $1 sliderLevel #{n}))"}.join(' ') +
|
13
13
|
'(log-noisy) (echo "copied slider levels from cue $1 to cue $2")',
|
14
|
+
'boost' => '(cue $1 sliderLevel $2 ++$3)',
|
15
|
+
'drop' => '(cue $1 sliderLevel $2 --$3)'
|
14
16
|
}.merge(copy_cue_actions)
|
15
17
|
end
|
16
18
|
|
data/lib/qcmd/commands.rb
CHANGED
@@ -281,16 +281,38 @@ sleep NUMBER
|
|
281
281
|
|
282
282
|
Will start cue number 3, then stop it two seconds later.
|
283
283
|
|
284
|
+
|
284
285
|
log-silent, log-noisy
|
285
286
|
|
286
287
|
Turn off output, turn it back on, respectively.
|
287
288
|
|
289
|
+
|
288
290
|
log-debug, log-info
|
289
291
|
|
290
292
|
Set output "level" to debug or info, respectively. Debug will tell you
|
291
293
|
everything qcmd is doing, in great detail. It's really just for development
|
292
294
|
purposes.
|
293
295
|
|
296
|
+
|
297
|
+
--, ++, //, **
|
298
|
+
|
299
|
+
These are modifiers can be used with a number on cue specific commands to
|
300
|
+
drop, raise, divide, or multiply the given value by the given amount,
|
301
|
+
respectively. For example, instead of using:
|
302
|
+
|
303
|
+
cue 1 sliderLevel 1 0
|
304
|
+
|
305
|
+
to set the value of volume slider 1 on cue 1 to 0 absolute, you can use:
|
306
|
+
|
307
|
+
cue 1 sliderLevel 1 ++0.2
|
308
|
+
|
309
|
+
to raise the current value of slider 1 on cue 1 by 0.2. To lower it by 0.2
|
310
|
+
you'd use "--0.2". The same for ** and //.
|
311
|
+
|
312
|
+
This is handy if you know you want to adjust the value of the cue setting by
|
313
|
+
a small amount but you don't know what the value is at the moment.
|
314
|
+
|
315
|
+
|
294
316
|
]
|
295
317
|
end
|
296
318
|
end
|
data/lib/qcmd/version.rb
CHANGED
data/spec/unit/action_spec.rb
CHANGED
@@ -10,6 +10,12 @@ class DeadHandler
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
def stubbed_modified_action modifier
|
14
|
+
action = Qcmd::CueAction.new ''
|
15
|
+
action.stub(:code) { [:cue, 1, :sliderLevel, 0, modifier] }
|
16
|
+
action
|
17
|
+
end
|
18
|
+
|
13
19
|
describe Qcmd::Action do
|
14
20
|
before do
|
15
21
|
Qcmd.context = Qcmd::Context.new
|
@@ -78,6 +84,67 @@ describe Qcmd::Action do
|
|
78
84
|
action = Qcmd::CueAction.new 'cue 1 name (cue 2 name)'
|
79
85
|
action.code[3].should be_an_instance_of(Qcmd::CueAction)
|
80
86
|
end
|
87
|
+
|
88
|
+
describe 'modifiers' do
|
89
|
+
describe 'positive' do
|
90
|
+
it 'should match int' do
|
91
|
+
action = stubbed_modified_action :'++1'
|
92
|
+
found = action.send(:trailing_modifier)
|
93
|
+
|
94
|
+
found.should_not be_nil
|
95
|
+
found.first.should eql(:+)
|
96
|
+
found.last.should eql('1')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should match float' do
|
100
|
+
action = stubbed_modified_action :'++1.2'
|
101
|
+
found = action.send(:trailing_modifier)
|
102
|
+
|
103
|
+
found.should_not be_nil
|
104
|
+
found.first.should eql(:+)
|
105
|
+
found.last.should eql('1.2')
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should match bare float' do
|
109
|
+
action = stubbed_modified_action :'++.2'
|
110
|
+
found = action.send(:trailing_modifier)
|
111
|
+
|
112
|
+
found.should_not be_nil
|
113
|
+
found.first.should eql(:+)
|
114
|
+
found.last.should eql('.2')
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'negative' do
|
120
|
+
it 'should match int' do
|
121
|
+
action = stubbed_modified_action :'--1'
|
122
|
+
found = action.send(:trailing_modifier)
|
123
|
+
|
124
|
+
found.should_not be_nil
|
125
|
+
found.first.should eql(:-)
|
126
|
+
found.last.should eql('1')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should match float' do
|
130
|
+
action = stubbed_modified_action :'--1.2'
|
131
|
+
found = action.send(:trailing_modifier)
|
132
|
+
|
133
|
+
found.should_not be_nil
|
134
|
+
found.first.should eql(:-)
|
135
|
+
found.last.should eql('1.2')
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should match bare float' do
|
139
|
+
action = stubbed_modified_action :'--.2'
|
140
|
+
found = action.send(:trailing_modifier)
|
141
|
+
|
142
|
+
found.should_not be_nil
|
143
|
+
found.first.should eql(:-)
|
144
|
+
found.last.should eql('.2')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
81
148
|
end
|
82
149
|
|
83
150
|
end
|
data/spec/unit/parser_spec.rb
CHANGED
@@ -26,6 +26,11 @@ describe Qcmd::Parser do
|
|
26
26
|
tokens.should eql([:cue, :'1.11.0'])
|
27
27
|
end
|
28
28
|
|
29
|
+
it 'should parse modifiers as symbols' do
|
30
|
+
tokens = Qcmd::Parser.parse 'cue number ++1 --1'
|
31
|
+
tokens.should eql([:cue, :number, :'++1', :'--1'])
|
32
|
+
end
|
33
|
+
|
29
34
|
it "should parse nested quotes" do
|
30
35
|
tokens = Qcmd::Parser.parse 'go "word word" 10 -12.3 "life \"is good\" yeah"'
|
31
36
|
tokens.should eql([:go, 'word word', 10, -12.3, 'life "is good" yeah'])
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qcmd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: true
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
|
8
|
+
- 16
|
9
|
+
- pre
|
10
|
+
version: 0.1.16.pre
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Adam Bachman
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2013-06-
|
18
|
+
date: 2013-06-05 00:00:00 -04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
@@ -192,11 +193,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
192
193
|
version: "0"
|
193
194
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
195
|
requirements:
|
195
|
-
- - "
|
196
|
+
- - ">"
|
196
197
|
- !ruby/object:Gem::Version
|
197
198
|
segments:
|
198
|
-
-
|
199
|
-
|
199
|
+
- 1
|
200
|
+
- 3
|
201
|
+
- 1
|
202
|
+
version: 1.3.1
|
200
203
|
requirements: []
|
201
204
|
|
202
205
|
rubyforge_project:
|