cue_dsl 1.0.0

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.
data/lib/cue_dsl.rb ADDED
@@ -0,0 +1,211 @@
1
+ # lib/cue_dsl.rb
2
+ require_relative "cue_dsl/version"
3
+ require_relative "cue_dsl/errors"
4
+ require_relative "cue_dsl/parameter"
5
+ require_relative "cue_dsl/filter_bank"
6
+ require_relative "cue_dsl/chain"
7
+ require_relative "cue_dsl/device"
8
+ require_relative "cue_dsl/matrix"
9
+ require_relative "cue_dsl/connect"
10
+ require_relative "cue_dsl/cue"
11
+ require_relative "cue_dsl/receivers_loader"
12
+ require_relative "cue_dsl/devices_config"
13
+ require_relative "cue_dsl/cheatsheet"
14
+
15
+ module CueDSL
16
+ class << self
17
+ attr_accessor :reset_system, :cheatsheet_path, :cue_numbers_path
18
+
19
+ def configure
20
+ yield self
21
+ end
22
+
23
+ def run(dsl_path, receivers_path: nil, devices_path: nil, out: $stdout, cheatsheet: nil)
24
+ receivers_path ||= File.join(File.dirname(dsl_path), "receivers.txt")
25
+ devices_path ||= File.join(File.dirname(dsl_path), "devices.yml")
26
+ cheatsheet ||= cheatsheet_path
27
+ Context.new(
28
+ dsl_path: dsl_path, receivers_path: receivers_path,
29
+ devices_path: devices_path, out: out, cheatsheet: cheatsheet
30
+ ).run
31
+ end
32
+ end
33
+
34
+ class Context
35
+ attr_reader :config, :receivers, :devices, :matrix, :system_params, :reset_verbs, :cues
36
+
37
+ def initialize(dsl_path:, receivers_path:, devices_path:, out:, cheatsheet:)
38
+ @dsl_path = dsl_path
39
+ @out = out
40
+ @cheatsheet = cheatsheet
41
+ @receivers = ReceiversLoader.load(receivers_path)
42
+ @config = DevicesConfig.load(devices_path)
43
+ @system_params = @receivers.system_params
44
+ @reset_verbs = @receivers.reset_verbs
45
+ @cues = []
46
+ @current_cue = nil
47
+ build_devices
48
+ end
49
+
50
+ def build_devices
51
+ @devices = {}
52
+ @receivers.devices.each do |prefix, params|
53
+ entry = @config.entries[prefix] or
54
+ raise ConfigurationError, "devices.yml: missing entry for #{prefix}"
55
+ dev = Device.new(
56
+ name: prefix, label: entry.label,
57
+ inputs: entry.inputs, outputs: entry.outputs,
58
+ parameters: params, filter_count: entry.filter_count
59
+ )
60
+ params.each_value { |p| dev.register_filter_fc(p) if p.kind == :filter_fc }
61
+ @devices[prefix] = dev
62
+ end
63
+ @matrix = Matrix.new(
64
+ rows: @config.matrix_rows, cols: @config.matrix_cols,
65
+ parameters: @receivers.matrix_params
66
+ )
67
+ @devices["MTX"] = @matrix
68
+ end
69
+
70
+ def run
71
+ instance_eval(File.read(@dsl_path), @dsl_path, 1)
72
+
73
+ lines, index = render_all
74
+
75
+ lines.each { |l| @out.puts l }
76
+
77
+ if @cheatsheet
78
+ File.write(@cheatsheet, Cheatsheet.render(
79
+ devices: @devices.values.reject { |d| d.is_a?(Matrix) },
80
+ matrix: @matrix,
81
+ system_params: @system_params,
82
+ reset_verbs: @reset_verbs
83
+ ))
84
+ end
85
+
86
+ if CueDSL.cue_numbers_path
87
+ File.write(CueDSL.cue_numbers_path, index.join("\n") + "\n")
88
+ end
89
+ end
90
+
91
+ def render_all
92
+ lines = []
93
+ index = []
94
+ global_reset = CueDSL.reset_system != false
95
+
96
+ @cues.each_with_index do |cue, i|
97
+ cue_reset = cue.reset_system?
98
+ cue_reset = global_reset if cue_reset.nil?
99
+
100
+ first_line = lines.length
101
+ index << "#{first_line} #{escape(cue.name)}" if cue_reset
102
+
103
+ nxt = @cues[i + 1]
104
+ preview = nxt ? "#{i + 1} - #{nxt.name}" : nil
105
+
106
+ cue.render(index: i, matrix: @matrix,
107
+ reset_system: cue_reset,
108
+ preview: preview).each { |l| lines << l }
109
+ end
110
+
111
+ [lines, index]
112
+ end
113
+
114
+ private
115
+
116
+ def escape(str)
117
+ str.gsub(/[ ,;]/) { |m| "\\#{m}" }
118
+ end
119
+
120
+ public
121
+ # ---- DSL verbs -------------------------------------------------------
122
+
123
+ def cue(name, reset_system: nil, &block)
124
+ line = caller_locations(1, 1).first.lineno
125
+ c = Cue.new(name, line, reset_system: reset_system)
126
+ @cues << c
127
+ prev = @current_cue
128
+ @current_cue = c
129
+ instance_eval(&block) if block
130
+ @current_cue = prev
131
+ c
132
+ end
133
+
134
+ def connect(*tokens)
135
+ raise Error, "connect outside cue" if @current_cue.nil?
136
+ raise ConnectionError,
137
+ "connect takes a chain like `dry >> filter`" if tokens.length != 1
138
+
139
+ chain = tokens.first
140
+ chain = Chain.new([chain]) if chain.is_a?(Device)
141
+ unless chain.is_a?(Chain)
142
+ raise ConnectionError, "connect expects a Chain, got #{chain.inspect}"
143
+ end
144
+ raise ConnectionError, "connect needs >=2 devices" if chain.devices.length < 2
145
+
146
+ @current_cue.record_chain_marker(chain.devices)
147
+ chain.devices.each do |d|
148
+ @current_cue.add_device(d)
149
+ d.bind(@current_cue)
150
+ end
151
+ end
152
+
153
+ def reset(sym)
154
+ raise Error, "reset outside cue" if @current_cue.nil?
155
+ raise Error, "unknown reset :#{sym}" unless @reset_verbs.include?(sym)
156
+ @current_cue.record_reset("reset_#{sym}_recv bang")
157
+ end
158
+
159
+ def comment(text, kind: :hash)
160
+ raise Error, "comment outside cue" if @current_cue.nil?
161
+ @current_cue.record_comment("#{kind == :gui ? '##' : '#'} #{text}")
162
+ end
163
+
164
+ def system
165
+ raise Error, "system outside cue" if @current_cue.nil?
166
+ SystemAccess.new(@current_cue, @system_params)
167
+ end
168
+
169
+ def method_missing(name, *args, &blk)
170
+ key = name.to_s.upcase
171
+ if @devices.key?(key)
172
+ dev = @devices[key]
173
+ if @current_cue && !dev.is_a?(Matrix)
174
+ @current_cue.add_device(dev)
175
+ dev.bind(@current_cue)
176
+ elsif @current_cue && dev.is_a?(Matrix)
177
+ dev.bind(@current_cue)
178
+ end
179
+ return dev
180
+ end
181
+ super
182
+ end
183
+
184
+ def respond_to_missing?(name, include_private = false)
185
+ @devices.key?(name.to_s.upcase) || super
186
+ end
187
+
188
+ class SystemAccess
189
+ AUTO_EMITTED = {
190
+ header_message: "cue name",
191
+ preview_cue: "the next cue's name"
192
+ }.freeze
193
+
194
+ def initialize(cue, params)
195
+ @cue = cue
196
+ params.each do |sym, param|
197
+ if AUTO_EMITTED.key?(sym)
198
+ define_singleton_method(sym) do |*|
199
+ raise Error, "system.#{sym} is emitted automatically from #{AUTO_EMITTED[sym]}; " \
200
+ "do not call it manually"
201
+ end
202
+ else
203
+ define_singleton_method(sym) do |value|
204
+ @cue.record_system(param.emit(value))
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cue_dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nicola Bernardini
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: minitest
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '5.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '5.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: simplecov
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.22'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.22'
54
+ description: Define live-electronics cues in Ruby; emit a Pure Data [text sequence]
55
+ stream on STDOUT, a cheatsheet and a cue line number index.
56
+ executables: []
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - LICENSE
61
+ - README.md
62
+ - bin/run.rb
63
+ - lib/cue_dsl.rb
64
+ - lib/cue_dsl/chain.rb
65
+ - lib/cue_dsl/cheatsheet.rb
66
+ - lib/cue_dsl/connect.rb
67
+ - lib/cue_dsl/cue.rb
68
+ - lib/cue_dsl/device.rb
69
+ - lib/cue_dsl/devices_config.rb
70
+ - lib/cue_dsl/errors.rb
71
+ - lib/cue_dsl/filter_bank.rb
72
+ - lib/cue_dsl/matrix.rb
73
+ - lib/cue_dsl/parameter.rb
74
+ - lib/cue_dsl/receivers_loader.rb
75
+ - lib/cue_dsl/version.rb
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '3.0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 4.0.14
94
+ specification_version: 4
95
+ summary: A DSL for generating Pure Data text sequence cue lists
96
+ test_files: []