lydown 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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