netlinx-erb 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.
- checksums.yaml +7 -0
- data/README.md +9 -0
- data/doc/Array.html +213 -0
- data/doc/Hash.html +266 -0
- data/doc/HashHelpers.html +413 -0
- data/doc/Helpers.html +2154 -0
- data/doc/NetLinx.html +128 -0
- data/doc/NetLinx/ERB.html +233 -0
- data/doc/NetLinx/ERB/HashHelpers.html +413 -0
- data/doc/NetLinx/ERB/Helpers.html +2157 -0
- data/doc/NetLinx/Rake.html +117 -0
- data/doc/NetLinx/Rake/ERB.html +117 -0
- data/doc/NetLinx/Rake/ERB/Compile.html +354 -0
- data/doc/NetLinx/Rake/ERB/GenerateERB.html +419 -0
- data/doc/NetLinx/Rake/ERB/GenerateRPC.html +349 -0
- data/doc/NetLinx/Rake/ERB/Lines.html +381 -0
- data/doc/NetLinx/Rake/Lines.html +381 -0
- data/doc/RPC.html +683 -0
- data/doc/String.html +322 -0
- data/doc/_index.html +248 -0
- data/doc/class_list.html +58 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +339 -0
- data/doc/file.README.html +84 -0
- data/doc/file.license.html +73 -0
- data/doc/file_list.html +63 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +84 -0
- data/doc/js/app.js +219 -0
- data/doc/js/full_list.js +181 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +237 -0
- data/doc/top-level-namespace.html +114 -0
- data/lib/netlinx-erb.rb +14 -0
- data/lib/netlinx/erb/erb.rb +19 -0
- data/lib/netlinx/erb/hash_helpers.rb +42 -0
- data/lib/netlinx/erb/helpers.rb +399 -0
- data/lib/netlinx/erb/rpc.rb +270 -0
- data/lib/netlinx/rake/erb.rb +26 -0
- data/lib/netlinx/rake/erb/generate_erb.rb +66 -0
- data/lib/netlinx/rake/erb/generate_rpc.rb +31 -0
- data/lib/netlinx/rake/erb/lines.rb +47 -0
- data/license.txt +21 -0
- data/template/Gemfile +9 -0
- data/template/README.md +130 -0
- data/template/Rakefile +11 -0
- data/template/rpc.axi +148 -0
- metadata +234 -0
data/lib/netlinx-erb.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
module NetLinx
|
5
|
+
module ERB
|
6
|
+
|
7
|
+
# @return a binding for ERB to evaluate code in.
|
8
|
+
# @example
|
9
|
+
# ERB.new(buffer, nil, '%<>-').result(NetLinx::ERB.binding)
|
10
|
+
def self.binding
|
11
|
+
@b ||= Module.new.instance_eval {
|
12
|
+
extend NetLinx::ERB::Helpers
|
13
|
+
# TODO: _config.rb instance variables should be injected here.
|
14
|
+
binding
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
module NetLinx
|
3
|
+
module ERB
|
4
|
+
|
5
|
+
# A collection of helper methods for use in Hash
|
6
|
+
module HashHelpers
|
7
|
+
|
8
|
+
# Template suffix (capitalized / unmodified).
|
9
|
+
def tmpl_suffix
|
10
|
+
Hash.instance_variable_get :@tmpl_suffix
|
11
|
+
end
|
12
|
+
|
13
|
+
# Template suffix for variables (lowercase).
|
14
|
+
def tmpl_var_suffix
|
15
|
+
Hash.instance_variable_get :@tmpl_var_suffix
|
16
|
+
end
|
17
|
+
|
18
|
+
# Append the @tmpl_suffix to each key in the hash.
|
19
|
+
def append_suffix
|
20
|
+
hash = self.map do |k,v|
|
21
|
+
key_name = "#{k}"
|
22
|
+
key_name += "_#{tmpl_suffix}" if tmpl_suffix and not tmpl_suffix.empty?
|
23
|
+
|
24
|
+
[key_name.to_sym, v]
|
25
|
+
end
|
26
|
+
|
27
|
+
Hash[hash]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Append the @tmpl_suffix to each key in the hash and overwrite this
|
31
|
+
# hash with the result.
|
32
|
+
def append_suffix!
|
33
|
+
hash = append_suffix
|
34
|
+
self.clear
|
35
|
+
self.merge! hash
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Hash.class_eval { include NetLinx::ERB::HashHelpers }
|
@@ -0,0 +1,399 @@
|
|
1
|
+
|
2
|
+
require_relative 'erb'
|
3
|
+
require_relative 'hash_helpers'
|
4
|
+
|
5
|
+
module NetLinx
|
6
|
+
module ERB
|
7
|
+
|
8
|
+
# A collection of code generation helper methods for use in NetLinx ERB files.
|
9
|
+
module Helpers
|
10
|
+
|
11
|
+
|
12
|
+
# @group Formatting
|
13
|
+
|
14
|
+
|
15
|
+
# Generate a group of lines for a given hash.
|
16
|
+
# @param hash [Hash]
|
17
|
+
# @param padding [String, Numeric] whitespace placed in front of the string.
|
18
|
+
# Can be a string of spaces, or a number representing the indentation level.
|
19
|
+
# @yield [key, value] elements from hash
|
20
|
+
# @return [String] lines of source code
|
21
|
+
def group hash, padding: nil, &block
|
22
|
+
padding = ' ' * (4 * padding) if padding.is_a?(Numeric)
|
23
|
+
hash.map { |key, value| block.call key, value }.compact.map { |str| padding.to_s + str }.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Left justify a block of code to line up on a type of character.
|
27
|
+
# Defaults to :equals (=).
|
28
|
+
#
|
29
|
+
# @param amount [Numeric] value of number of spaces, or the longest key in a hash.
|
30
|
+
# @param type [:equals, :colon, :comma, :comma_2, :semicolon] character to justify on.
|
31
|
+
# @return [String] a group of justified lines of source code.
|
32
|
+
def justify str, amount: nil, type: nil
|
33
|
+
# justification_amount = amount.is_a?(Numeric) ? amount : amount.map { |key, _| key.to_s.size }.max
|
34
|
+
|
35
|
+
lines = str.split "\n"
|
36
|
+
|
37
|
+
justify_types = {
|
38
|
+
equals: lines.map { |line| line.index "=" }.compact.max,
|
39
|
+
colon: lines.map { |line| line.index ":" }.compact.max,
|
40
|
+
comma: lines.map { |line| line.index "," }.compact.max,
|
41
|
+
comma_2: lines.map { |line| line.index "," }.compact.max,
|
42
|
+
semicolon: lines.map { |line| line.index ";" }.compact.max,
|
43
|
+
}
|
44
|
+
|
45
|
+
# Types that will be chosen from automatically if no type is specified
|
46
|
+
auto_justify_types = [:equals, :colon]
|
47
|
+
|
48
|
+
justify_by = justify_types.select { |k,v|
|
49
|
+
auto_justify_types.include?(k) && !v.nil?
|
50
|
+
}.min
|
51
|
+
justify_by = justify_by.first if justify_by
|
52
|
+
justify_by = type if type
|
53
|
+
|
54
|
+
justify_amount = amount || justify_types[justify_by] || 0
|
55
|
+
|
56
|
+
# Rebuild each line with the appropriate justification.
|
57
|
+
lines.map! { |line|
|
58
|
+
output = ''
|
59
|
+
|
60
|
+
case justify_by
|
61
|
+
when :equals
|
62
|
+
line =~ /(.*?)(=.*)/
|
63
|
+
output = $2.nil? ? line : $1.ljust(justify_amount) + $2
|
64
|
+
when :colon
|
65
|
+
line =~ /(.*?\:)\s*(.*)/
|
66
|
+
output = $2.nil? ? line : $1.ljust(justify_amount + 1) + ' ' + $2
|
67
|
+
when :comma
|
68
|
+
line =~ /(.*?\,)\s*(.*)/
|
69
|
+
output = $2.nil? ? line : $1.ljust(justify_amount + 1) + ' ' + $2
|
70
|
+
when :comma_2
|
71
|
+
line =~ /(.*?\,.*?\,)\s*(.*)/
|
72
|
+
output = $2.nil? ? line : $1.ljust(justify_amount + 1) + ' ' + $2
|
73
|
+
when :semicolon
|
74
|
+
line =~ /(.*?\;)\s*(.*)/
|
75
|
+
output = $2.nil? ? line : $1.ljust(justify_amount + 1) + ' ' + $2
|
76
|
+
else
|
77
|
+
line
|
78
|
+
end
|
79
|
+
}.join "\n"
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# @group Code Generation
|
84
|
+
|
85
|
+
|
86
|
+
# Print the list of devices.
|
87
|
+
# @param h [Hash] device names as keys.
|
88
|
+
# @param justify [Numeric] column number to justify equals symbol (=) on.
|
89
|
+
# @return [String] a group of justified lines of source code.
|
90
|
+
def print_device_hash h, justify: nil
|
91
|
+
# TODO: Refactor to use #justify.
|
92
|
+
max_len = h.map { |name, value| name.size }.max
|
93
|
+
h.map { |name, value| "dv#{name.to_s.upcase.ljust justify || max_len} = #{value};" }.join("\n")
|
94
|
+
end
|
95
|
+
|
96
|
+
# Print the list of constants.
|
97
|
+
# @param h [Hash] constant names as keys.
|
98
|
+
# @param justify [Numeric] column number to justify equals symbol (=) on.
|
99
|
+
# @return [String] a group of justified lines of source code.
|
100
|
+
def print_constant_hash h, justify: nil
|
101
|
+
# TODO: Refactor to use #justify.
|
102
|
+
max_len = h.map { |name, value| name.size }.max
|
103
|
+
h.map { |name, value| "#{name.to_s.upcase.ljust justify || max_len} = #{value};" }.join("\n")
|
104
|
+
end
|
105
|
+
|
106
|
+
# Print the list of variables.
|
107
|
+
# Format:
|
108
|
+
# {
|
109
|
+
# var_name: { type: :integer, default: 0, comment: 'my var' }
|
110
|
+
# }
|
111
|
+
# @param h [Hash] variable names as keys.
|
112
|
+
# @return [String] a group of justified lines of source code.
|
113
|
+
def print_variable_hash h
|
114
|
+
justify group(h) { |name, params|
|
115
|
+
type = params.fetch :type, :integer
|
116
|
+
default = params.fetch :default, nil
|
117
|
+
comment = params.fetch :comment, nil
|
118
|
+
|
119
|
+
output = "#{type} #{name.to_s.downcase}"
|
120
|
+
output += " = #{default}" if default
|
121
|
+
output += ";"
|
122
|
+
output += " // #{comment}" if comment
|
123
|
+
output
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
# Generate instance variables for the DEFINE_CONSTANTS section
|
128
|
+
# from the given hash keys.
|
129
|
+
# Appends @tmpl_suffix if set.
|
130
|
+
# @see #print_variable_hash #print_variable_hash - for formatting
|
131
|
+
def generate_constant_ivars h, append_suffix: false
|
132
|
+
h.each_key do |key|
|
133
|
+
value = key.to_s.upcase
|
134
|
+
value = "#{value}_#{@tmpl_suffix.to_s.upcase}" if @tmpl_suffix and append_suffix
|
135
|
+
|
136
|
+
instance_variable_set :"@#{key.to_sym}", value
|
137
|
+
end
|
138
|
+
|
139
|
+
h
|
140
|
+
end
|
141
|
+
|
142
|
+
# Generate instance variables for the DEFINE_VARIABLES section
|
143
|
+
# from the given hash keys.
|
144
|
+
# Appends @tmpl_var_suffix if set.
|
145
|
+
# @see #print_variable_hash #print_variable_hash - for formatting
|
146
|
+
def generate_variable_ivars h, append_suffix: true
|
147
|
+
h.each_key do |key|
|
148
|
+
value = key.to_s.downcase
|
149
|
+
value = "#{value}_#{@tmpl_suffix.to_s.downcase}" if @tmpl_suffix and append_suffix
|
150
|
+
|
151
|
+
instance_variable_set :"@#{key.to_sym}", value
|
152
|
+
end
|
153
|
+
|
154
|
+
h
|
155
|
+
end
|
156
|
+
|
157
|
+
# Automatically comment out the input unless the condition is met.
|
158
|
+
# @param str [String] NetLinx source code string
|
159
|
+
# @param condition comments out the source code string if evaluates to false or nil
|
160
|
+
# @return [String] NetLinx source code
|
161
|
+
def auto_comment str, condition
|
162
|
+
condition ? str : str.split("\n").map { |line| "// " + line }.join("\n")
|
163
|
+
end
|
164
|
+
|
165
|
+
# Generate button events for the given hash of buttons.
|
166
|
+
# @param buttons [Hash] button constants
|
167
|
+
# @param device [String] touch panel device constant.
|
168
|
+
# @dvTP comes from ERB template.
|
169
|
+
# @return [String] \[dev, chan\] source code
|
170
|
+
def button_event buttons, device = @dvTP
|
171
|
+
buttons.map { |name, _| "button_event[#{device}, #{name}]" }.join("\n")
|
172
|
+
end
|
173
|
+
|
174
|
+
# Generate a button_event block for the given hash of buttons.
|
175
|
+
# @param buttons [Hash] button constants
|
176
|
+
# @param kwargs [Hash]
|
177
|
+
# @option kwargs [String] :function name of the function to call in the switch block
|
178
|
+
# @option kwargs [Symbol, nil] :remap name of symbol to use to {Hash#remap} the hash.
|
179
|
+
# This is a convenience arg for readability; the hash can also be remapped
|
180
|
+
# before passed into this method.
|
181
|
+
# @option kwargs [String] :device touch panel device constant.
|
182
|
+
# @dvTP comes from ERB template.
|
183
|
+
# @option kwargs [String, Numeric] :padding (3) whitespace placed in front of the string.
|
184
|
+
# Can be a string of spaces, or a number representing the indentation level.
|
185
|
+
# @option kwargs [Boolean] :momentary (false) adds a `to` statement for momentary button feedback
|
186
|
+
# @option kwargs [Boolean] :hold_block (false) create a hold block for the event
|
187
|
+
# @option kwargs [Boolean] :hold_time (0.6) repeat time for the hold block
|
188
|
+
# @yield [value, name] option to create a custom function call string.
|
189
|
+
# Modifies the function arguments if :function is set, otherwise modifies
|
190
|
+
# the entire function call string.
|
191
|
+
# @yieldparam value value of the buttons hash for the given key. Accounts for remap.
|
192
|
+
# @yieldparam name [Symbol] key of the buttons hash
|
193
|
+
# @yieldreturn [String] function string
|
194
|
+
#
|
195
|
+
# @example
|
196
|
+
# button_event_block bluray_key_constants.remap(:key),
|
197
|
+
# function: 'bluray_key', momentary: true
|
198
|
+
#
|
199
|
+
# button_event_block channel_strip_constants.select {|k,_| k.to_s.end_with? "_UP"},
|
200
|
+
# function: 'audio_increment_volume', remap: :audio, hold_block: true, momentary: true
|
201
|
+
#
|
202
|
+
# # Use block to create function string.
|
203
|
+
# # :function not set
|
204
|
+
# button_event_block(video_source_constants) { |h|
|
205
|
+
# "video_patch(#{h[:input]}, #{h[:dest]})"
|
206
|
+
# }
|
207
|
+
#
|
208
|
+
# # Use block to create parameters string.
|
209
|
+
# # :function is set
|
210
|
+
# button_event_block(video_source_constants, function: 'video_patch') { |h|
|
211
|
+
# "#{h[:input]}, #{h[:dest]}"
|
212
|
+
# }
|
213
|
+
#
|
214
|
+
# # Use block to specify an array of parameters.
|
215
|
+
# # :function is set
|
216
|
+
# button_event_block(video_source_constants, function: 'video_patch') { |h|
|
217
|
+
# [h[:input], h[:dest]]
|
218
|
+
# }
|
219
|
+
#
|
220
|
+
def button_event_block buttons, **kwargs, &block
|
221
|
+
function = kwargs.fetch :function, nil
|
222
|
+
device = kwargs.fetch :device, @dvTP
|
223
|
+
remap = kwargs.fetch :remap, nil
|
224
|
+
padding = kwargs.fetch :padding, 3
|
225
|
+
momentary = kwargs.fetch :momentary, false
|
226
|
+
hold_block = kwargs.fetch :hold_block, false
|
227
|
+
hold_time = kwargs.fetch :hold_time, 0.6
|
228
|
+
|
229
|
+
buttons = buttons.remap(remap) if remap
|
230
|
+
|
231
|
+
case_string = justify group(buttons, padding: padding) { |name, value|
|
232
|
+
str = if block_given?
|
233
|
+
block_val = block.call value, name
|
234
|
+
block_val = block_val.join ', ' if block_val.is_a? Array
|
235
|
+
|
236
|
+
if function
|
237
|
+
"#{function}(#{block_val})"
|
238
|
+
else
|
239
|
+
"#{block_val}"
|
240
|
+
end
|
241
|
+
else
|
242
|
+
"#{function}(#{value})"
|
243
|
+
end
|
244
|
+
|
245
|
+
auto_comment "case #{name}: #{str};", value
|
246
|
+
}
|
247
|
+
|
248
|
+
momentary_string = momentary ? "\n to[button.input];\n " : ''
|
249
|
+
|
250
|
+
output = <<EOS
|
251
|
+
#{button_event buttons, device}
|
252
|
+
{
|
253
|
+
push:
|
254
|
+
{#{momentary_string}
|
255
|
+
switch (button.input.channel)
|
256
|
+
{
|
257
|
+
#{ case_string }
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
EOS
|
262
|
+
|
263
|
+
if hold_block
|
264
|
+
hold_string = <<EOS
|
265
|
+
hold[#{hold_time}, repeat]:
|
266
|
+
{
|
267
|
+
switch (button.input.channel)
|
268
|
+
{
|
269
|
+
#{ case_string }
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
EOS
|
274
|
+
output += hold_string
|
275
|
+
end
|
276
|
+
|
277
|
+
output +=
|
278
|
+
<<EOS
|
279
|
+
release: {}
|
280
|
+
}
|
281
|
+
EOS
|
282
|
+
output.chomp
|
283
|
+
end
|
284
|
+
|
285
|
+
# Generate an empty HiQnet address string.
|
286
|
+
#
|
287
|
+
# @example
|
288
|
+
# # Generates:
|
289
|
+
# '0x000000000000'
|
290
|
+
def hiqnet_empty
|
291
|
+
'0x' + ('0' * 12)
|
292
|
+
end
|
293
|
+
|
294
|
+
# Send a touch panel command to show or hide a control.
|
295
|
+
# @param control [Symbol, String] address or constant of a control
|
296
|
+
# @param show [Boolean, Numeric, String] 0/1 print verbatim.
|
297
|
+
# true/fase convert to 0/1.
|
298
|
+
# string expression is wrapped in itoa().
|
299
|
+
#
|
300
|
+
# @example
|
301
|
+
# ^SHO-<control>,<0|1>
|
302
|
+
def show_control control, show, device: @dvTP
|
303
|
+
str = "send_command #{device}, \"'^SHO-', itoa(#{control}), ',"
|
304
|
+
|
305
|
+
if show.is_a? Fixnum
|
306
|
+
str += "#{show}'"
|
307
|
+
elsif show == true or show == false or show == nil
|
308
|
+
str += "#{show ? 1 : 0}'"
|
309
|
+
else
|
310
|
+
str += "', itoa(#{show})"
|
311
|
+
end
|
312
|
+
|
313
|
+
str += "\";"
|
314
|
+
end
|
315
|
+
|
316
|
+
# Run ERB on the given template file.
|
317
|
+
# @param template_file [String] file path
|
318
|
+
# @return [String] ERB output.
|
319
|
+
# @raise [LoadError] template not found
|
320
|
+
def execute_erb template_file
|
321
|
+
raise LoadError, "Template not found: #{template_file}" unless File.exists? template_file
|
322
|
+
$AUTOGEN_HEADER + ::ERB.new(File.read(template_file), nil, '%<>-')
|
323
|
+
.result(NetLinx::ERB.binding)
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
# @group Other
|
328
|
+
|
329
|
+
|
330
|
+
# Ensures button number constants haven't been unintentionally duplicated.
|
331
|
+
# @param hashes [*Hash]
|
332
|
+
# @raise if two keys have the same value.
|
333
|
+
def check_for_duplicate_values *hashes
|
334
|
+
raise NotImplementedError
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# :nodoc:
|
342
|
+
class Hash
|
343
|
+
|
344
|
+
# Reconstructs a single level hash out of a hash with nested parameters.
|
345
|
+
# @param nested_key use the value associated with this key in the nested hash
|
346
|
+
# @return [Hash] keys mapped to the set of values specified
|
347
|
+
#
|
348
|
+
# @example
|
349
|
+
# buttons = {
|
350
|
+
# :TOUCH_PANEL_BUTTON_1 => { btn: 1, matrix_input: :MTX_IN_DVD },
|
351
|
+
# :TOUCH_PANEL_BUTTON_2 => { btn: 2, matrix_input: :MTX_IN_VCR }
|
352
|
+
# }
|
353
|
+
#
|
354
|
+
# # buttons.remap(:btn) will return a hash of touch panel button
|
355
|
+
# # symbols with the :btn numbers mapped as the values, and
|
356
|
+
# # :matrix_input will be discarded.
|
357
|
+
def remap nested_key
|
358
|
+
self.map { |k,v| [k, v[nested_key]] }.to_h
|
359
|
+
end
|
360
|
+
|
361
|
+
end
|
362
|
+
|
363
|
+
# Patch Array#to_h into Ruby 2.0
|
364
|
+
unless RUBY_VERSION >= '2.1.0'
|
365
|
+
# :nodoc:
|
366
|
+
class Array
|
367
|
+
# Convert array to hash.
|
368
|
+
def to_h
|
369
|
+
Hash[self]
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# :nodoc:
|
375
|
+
class String
|
376
|
+
|
377
|
+
# Intended for initializing struct constants.
|
378
|
+
def remove_comma_after_last_item
|
379
|
+
self.gsub(/(?<=\}),(.*?)\z/, ' \1')
|
380
|
+
end
|
381
|
+
|
382
|
+
# Convert a string to a HiQnet address struct.
|
383
|
+
# Can include state variable.
|
384
|
+
# @param sv [String, Integer, nil], state variable
|
385
|
+
#
|
386
|
+
# @example
|
387
|
+
# '0x100203000103'.to_hiqnet(0x0000)
|
388
|
+
# # Generates:
|
389
|
+
# {$10, $02, $03, $00, $01, $03, $00, $00},
|
390
|
+
def to_hiqnet sv = nil
|
391
|
+
sv ||= ''
|
392
|
+
sv = sv.is_a?(Fixnum) ? sv.to_s(16) : sv.to_s
|
393
|
+
sv = sv.rjust(4, '0') unless sv.empty?
|
394
|
+
|
395
|
+
address = self + sv
|
396
|
+
"{#{address.gsub(/\A0x/, '').upcase.scan(/../).map {|s| '$' + s}.join(', ')}},"
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|