lydown 0.9.0 → 0.10.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +159 -2
  3. data/lib/lydown.rb +8 -2
  4. data/lib/lydown/cache.rb +54 -0
  5. data/lib/lydown/cli.rb +1 -0
  6. data/lib/lydown/cli/commands.rb +27 -9
  7. data/lib/lydown/cli/compiler.rb +218 -54
  8. data/lib/lydown/cli/diff.rb +1 -1
  9. data/lib/lydown/cli/proofing.rb +3 -3
  10. data/lib/lydown/cli/signals.rb +23 -0
  11. data/lib/lydown/cli/support.rb +23 -1
  12. data/lib/lydown/core_ext.rb +41 -5
  13. data/lib/lydown/{rendering/defaults.yml → defaults.yml} +3 -3
  14. data/lib/lydown/errors.rb +3 -0
  15. data/lib/lydown/lilypond.rb +73 -31
  16. data/lib/lydown/ly_lib/lib.ly +297 -0
  17. data/lib/lydown/parsing.rb +1 -2
  18. data/lib/lydown/parsing/lydown.treetop +16 -10
  19. data/lib/lydown/parsing/nodes.rb +29 -5
  20. data/lib/lydown/rendering.rb +32 -6
  21. data/lib/lydown/rendering/command.rb +79 -2
  22. data/lib/lydown/rendering/figures.rb +29 -8
  23. data/lib/lydown/rendering/literal.rb +7 -0
  24. data/lib/lydown/rendering/movement.rb +61 -0
  25. data/lib/lydown/rendering/music.rb +37 -5
  26. data/lib/lydown/rendering/notes.rb +26 -8
  27. data/lib/lydown/rendering/settings.rb +41 -13
  28. data/lib/lydown/rendering/skipping.rb +43 -10
  29. data/lib/lydown/rendering/staff.rb +72 -16
  30. data/lib/lydown/templates.rb +8 -2
  31. data/lib/lydown/templates/lilypond_doc.erb +10 -1
  32. data/lib/lydown/templates/movement.erb +87 -34
  33. data/lib/lydown/templates/multi_voice.erb +1 -1
  34. data/lib/lydown/templates/part.erb +83 -55
  35. data/lib/lydown/templates/variables.erb +38 -0
  36. data/lib/lydown/version.rb +1 -1
  37. data/lib/lydown/work.rb +39 -26
  38. data/lib/lydown/work_context.rb +252 -14
  39. metadata +138 -8
  40. data/lib/lydown/rendering/lib.ly +0 -88
@@ -32,14 +32,14 @@ module Lydown
32
32
  def reset(mode)
33
33
  case mode
34
34
  when :work
35
- @context[:time] = '4/4'
36
- @context[:tempo] = nil
37
- @context[:cadenza_mode] = nil
38
- @context[:key] = 'c major'
39
- @context[:pickup] = nil
40
- @context[:beaming] = nil
41
- @context[:end_barline] = nil
42
35
  @context[:part] = nil
36
+ set_setting(:time, '4/4')
37
+ set_setting(:tempo, nil)
38
+ @context[:cadenza_mode] = nil
39
+ set_setting(:key, 'c major')
40
+ set_setting(:pickup, nil)
41
+ set_setting(:beaming, nil)
42
+ set_setting(:end_barline, nil)
43
43
  when :movement
44
44
  @context[:part] = nil
45
45
  end
@@ -95,23 +95,102 @@ module Lydown
95
95
 
96
96
  if filter = opts[:parts]
97
97
  filter = [filter] unless filter.is_a?(Array)
98
+ filter += opts[:include_parts] if opts[:include_parts]
98
99
  end
99
- filtered[:movements].each do |name, m|
100
+
101
+ filtered[:movements].each do |movement_name, m|
100
102
  # delete default part if other parts are present
101
103
  if m[:parts].size > 1
102
104
  m[:parts].delete('')
103
105
  end
104
106
 
105
- if filter
106
- m[:parts].select! do |pname, p|
107
- filter.include?(pname.to_s)
108
- end
109
- end
107
+ filter_movement_parts(movement_name, m, filter)
110
108
  end
111
109
 
112
- filtered
110
+ WorkContext.new(nil, filtered)
111
+ end
112
+
113
+ DEFAULT_SOURCE_STREAMS = %w{music}
114
+
115
+ # Parts are filtered as follows:
116
+ #
117
+ # - Parts for which the render_modes do not include the current mode
118
+ # are rejected.
119
+ # - If a filter is provided, only the specified parts are selected, and any
120
+ # colla parte parts are added if found.
121
+ # - Part includes are checked and added as well
122
+ def filter_movement_parts(movement_name, m, filter)
123
+ mode = self['options/mode']
124
+ if DEFAULT_RENDER_MODES.include?(mode)
125
+ m[:parts].select! do |part_name|
126
+ part_render_modes(movement_name, part_name).include?(mode)
127
+ end
128
+ end
129
+
130
+ select_filter_parts(movement_name, m, filter) if filter
131
+ add_part_includes(movement_name, m)
113
132
  end
114
133
 
134
+ DEFAULT_RENDER_MODES = [:part, :score]
135
+
136
+ def part_render_modes(movement_name, part_name)
137
+ modes = get_setting(:render_modes, part: part_name, movement: movement_name)
138
+ if modes
139
+ modes.split(',').map {|m| m.strip.to_sym}
140
+ else
141
+ DEFAULT_RENDER_MODES
142
+ end
143
+ end
144
+
145
+ def select_filter_parts(movement_name, m, filter)
146
+ m[:parts].select! {|part_name, p| filter.include?(part_name)}
147
+
148
+ # go over filter and check for colla parte
149
+ filter.each do |part_name|
150
+ unless m[:parts].keys.include?(part_name)
151
+ if source = part_source(movement_name, part_name)
152
+ part_path = "parts/#{part_name}"
153
+ source_path = "movements/#{movement_name}/parts/#{source}"
154
+
155
+ source_streams = ['settings']
156
+ if stream_list = part_source_streams(movement_name, part_name)
157
+ source_streams += stream_list.split(',').map(&:strip)
158
+ else
159
+ source_streams += DEFAULT_SOURCE_STREAMS
160
+ end
161
+
162
+ m[part_path] = source_streams.inject({}) do |hash, stream|
163
+ hash[stream] = self["#{source_path}/#{stream}"]
164
+ hash
165
+ end.deep!
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ def add_part_includes(movement_name, m)
172
+ # check for part includes
173
+ if part = self['options/parts']
174
+ part = part[0] if part.is_a?(Array)
175
+ includes = get_setting(:include_parts,
176
+ movement: movement_name, part: part)
177
+
178
+ return unless includes
179
+
180
+ includes = includes.split(',').map(&:strip)
181
+
182
+ includes.each do |included_part|
183
+ # If the included part does not exist, try to find its source
184
+ part_hash = self["movements/#{movement_name}/parts/#{included_part}"]
185
+ unless part_hash
186
+ source = part_source(movement_name, included_part)
187
+ part_hash = self["movements/#{movement_name}/parts/#{source}"]
188
+ end
189
+ m["parts/#{included_part}"] ||= part_hash
190
+ end
191
+ end
192
+ end
193
+
115
194
  def [](key)
116
195
  @context[key]
117
196
  end
@@ -121,6 +200,10 @@ module Lydown
121
200
  end
122
201
 
123
202
  def emit(path, *content)
203
+ if self['process/mode']
204
+ return unless self['process/mode'] == render_mode
205
+ end
206
+
124
207
  stream = current_stream(path)
125
208
 
126
209
  content.each {|c| stream << c}
@@ -148,5 +231,160 @@ module Lydown
148
231
 
149
232
  @context[path] = settings
150
233
  end
234
+
235
+ def settings_path(movement, part)
236
+ if part
237
+ "movements/#{movement}/parts/#{part}/settings"
238
+ elsif movement && !movement.empty?
239
+ "movements/#{movement}/settings"
240
+ else
241
+ "global/settings"
242
+ end
243
+ end
244
+
245
+ def query_setting(movement, part, path)
246
+ path = "#{settings_path(movement, part)}/#{path}"
247
+ value = @context[path]
248
+ unless value.nil?
249
+ @temp_setting_value = value
250
+ true
251
+ else
252
+ false
253
+ end
254
+ end
255
+
256
+ def query_defaults(path)
257
+ value = DEFAULTS[path]
258
+ unless value.nil?
259
+ @temp_setting_value = value
260
+ true
261
+ else
262
+ false
263
+ end
264
+ end
265
+
266
+ def query_setting_tree(movement, part, path)
267
+ path = "#{settings_path(movement, part)}/#{path}"
268
+ @context[path] || {}
269
+ end
270
+
271
+ def get_setting(path, opts = {})
272
+ # In order to allow false values for settings, we create
273
+ # a temporary instance variable, and use it to store the
274
+ # setting value once it's found. That way we can use the
275
+ # || operator to stop searching once we've found it.
276
+ @temp_setting_value = nil
277
+ if opts[:part]
278
+ parts_section_path = "parts/#{opts[:part]}/#{path}"
279
+
280
+ query_setting(opts[:movement], opts[:part], path) ||
281
+ query_setting(nil, opts[:part], path) ||
282
+ query_setting(opts[:movement], nil, path) ||
283
+ query_setting(nil, nil, path) ||
284
+
285
+ # search in parts section
286
+ query_setting(opts[:movement], nil, parts_section_path) ||
287
+ query_setting(nil, nil, parts_section_path) ||
288
+
289
+ query_defaults("parts/#{opts[:part]}/#{path}") ||
290
+ query_defaults(path)
291
+ else
292
+ query_setting(opts[:movement], nil, path) ||
293
+ query_setting(nil, nil, path) ||
294
+ query_defaults(path)
295
+ end
296
+ @temp_setting_value
297
+ end
298
+
299
+ # Get setting while code is being translated
300
+ def get_current_setting(path)
301
+ get_setting(path, current_setting_opts)
302
+ end
303
+
304
+ def current_setting_opts
305
+ {movement: @context[:movement], part: @context[:part]}
306
+ end
307
+
308
+ # Returns a merged tree of the settings from different levels
309
+ def get_merged_setting_tree(path, opts)
310
+ tree = (DEFAULTS[path] || {}).deep_merge(
311
+ query_setting_tree(nil, nil, path))
312
+
313
+ if opts[:movement]
314
+ tree.deep_merge! query_setting_tree(opts[:movement], nil, path)
315
+ else
316
+ tree.deep!
317
+ end
318
+ end
319
+
320
+ def colla_parte_map(movement_name)
321
+ parts_settings = get_merged_setting_tree(:parts, movement: movement_name)
322
+ colla_parte = get_merged_setting_tree(:colla_parte, movement: movement_name)
323
+
324
+ map = Hash.new {|h, k| h[k] = []}
325
+ parts_settings.each do |name, settings|
326
+ if source = settings['source']
327
+ map[source] << name
328
+ end
329
+ end
330
+
331
+ colla_parte.each do |source, parts|
332
+ parts.split(',').map(&:strip).inject(map[source]) do |m, p|
333
+ m << p unless m.include?(p); m
334
+ end
335
+ end
336
+
337
+ map
338
+ end
339
+
340
+ def part_source(movement_name, part_name)
341
+ parts_settings = get_merged_setting_tree(:parts, movement: movement_name)
342
+ if source = parts_settings["#{part_name}/source"]
343
+ return source
344
+ else
345
+ colla_parte = get_merged_setting_tree(:colla_parte, movement: movement_name)
346
+ colla_parte.each do |source, parts|
347
+ if parts.split(',').map(&:strip).include?(part_name)
348
+ return source
349
+ end
350
+ end
351
+ end
352
+ nil
353
+ end
354
+
355
+ def part_source_streams(movement_name, part_name)
356
+ parts_settings = get_merged_setting_tree(:parts, movement: movement_name)
357
+ parts_settings["#{part_name}/source_streams"]
358
+ end
359
+
360
+ def set_setting(path, value)
361
+ path = "#{settings_path(@context[:movement], @context[:part])}/#{path}"
362
+ @context[path] = value
363
+ end
364
+
365
+ def render_mode
366
+ self['options/mode'] || self['render_opts/mode']
367
+ end
368
+
369
+ def to_msgpack
370
+ @context.to_msgpack
371
+ end
372
+
373
+ # Returns a list of parts to extract for the specified opts. Only parts
374
+ # that should be extracted (based on the render_modes setting) are included.
375
+ def part_list_for_extraction(opts)
376
+ parts = []
377
+ return parts unless @context[:movements]
378
+
379
+ @context[:movements].each do |mname, m|
380
+ m[:parts].each do |pname, p|
381
+ # Add only parts that render in part mode
382
+ if part_render_modes(mname, pname).include?(:part)
383
+ parts << pname unless (pname == '') || parts.include?(pname)
384
+ end
385
+ end
386
+ end
387
+ parts
388
+ end
151
389
  end
152
390
  end
metadata CHANGED
@@ -1,29 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lydown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-06 00:00:00.000000000 Z
11
+ date: 2015-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: 1.6.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: 1.6.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: diff-lcs
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: escape_utils
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.19.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.19.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: directory_watcher
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 1.5.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.5.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: ruby-progressbar
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.7.5
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.7.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: parallel
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 1.6.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.6.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: msgpack
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 0.6.2
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 0.6.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: combine_pdf
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '='
130
+ - !ruby/object:Gem::Version
131
+ version: 0.2.5
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '='
137
+ - !ruby/object:Gem::Version
138
+ version: 0.2.5
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '='
144
+ - !ruby/object:Gem::Version
145
+ version: 3.2.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '='
151
+ - !ruby/object:Gem::Version
152
+ version: 3.2.0
27
153
  description: Lydown is a language and tool for music notation
28
154
  email: ciconia@gmail.com
29
155
  executables:
@@ -35,17 +161,21 @@ files:
35
161
  - README.md
36
162
  - bin/lydown
37
163
  - lib/lydown.rb
164
+ - lib/lydown/cache.rb
38
165
  - lib/lydown/cli.rb
39
166
  - lib/lydown/cli/commands.rb
40
167
  - lib/lydown/cli/compiler.rb
41
168
  - lib/lydown/cli/diff.rb
42
169
  - lib/lydown/cli/output.rb
43
170
  - lib/lydown/cli/proofing.rb
171
+ - lib/lydown/cli/signals.rb
44
172
  - lib/lydown/cli/support.rb
45
173
  - lib/lydown/cli/translation.rb
46
174
  - lib/lydown/core_ext.rb
175
+ - lib/lydown/defaults.yml
47
176
  - lib/lydown/errors.rb
48
177
  - lib/lydown/lilypond.rb
178
+ - lib/lydown/ly_lib/lib.ly
49
179
  - lib/lydown/parsing.rb
50
180
  - lib/lydown/parsing/lydown.treetop
51
181
  - lib/lydown/parsing/nodes.rb
@@ -53,9 +183,8 @@ files:
53
183
  - lib/lydown/rendering/base.rb
54
184
  - lib/lydown/rendering/command.rb
55
185
  - lib/lydown/rendering/comments.rb
56
- - lib/lydown/rendering/defaults.yml
57
186
  - lib/lydown/rendering/figures.rb
58
- - lib/lydown/rendering/lib.ly
187
+ - lib/lydown/rendering/literal.rb
59
188
  - lib/lydown/rendering/lyrics.rb
60
189
  - lib/lydown/rendering/movement.rb
61
190
  - lib/lydown/rendering/music.rb
@@ -70,6 +199,7 @@ files:
70
199
  - lib/lydown/templates/movement.erb
71
200
  - lib/lydown/templates/multi_voice.erb
72
201
  - lib/lydown/templates/part.erb
202
+ - lib/lydown/templates/variables.erb
73
203
  - lib/lydown/translation.rb
74
204
  - lib/lydown/translation/ripple.rb
75
205
  - lib/lydown/translation/ripple/nodes.rb