gitara 0.5.0 → 0.6.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 (47) hide show
  1. data/.gitignore +2 -0
  2. data/.yardopts +5 -0
  3. data/CHANGELOG.markdown +5 -0
  4. data/README.markdown +135 -99
  5. data/examples/tab-with-repeats.ly +117 -0
  6. data/examples/tab-with-repeats.rb +19 -0
  7. data/gitara.gemspec +3 -0
  8. data/lib/gitara.rb +5 -3
  9. data/lib/gitara/dsl.rb +13 -0
  10. data/lib/gitara/node/alternative.rb +14 -0
  11. data/lib/gitara/node/bar.rb +3 -1
  12. data/lib/gitara/node/base.rb +22 -24
  13. data/lib/gitara/node/base/chorded_version.rb +1 -4
  14. data/lib/gitara/node/base/node_version.rb +35 -0
  15. data/lib/gitara/node/base/stanza_version.rb +1 -4
  16. data/lib/gitara/node/base/voiced_version.rb +5 -6
  17. data/lib/gitara/node/repeat.rb +10 -0
  18. data/lib/gitara/node/tab.rb +3 -5
  19. data/lib/gitara/utilities.rb +8 -0
  20. data/lib/gitara/version.rb +1 -1
  21. data/lib/gitara/voice.rb +2 -0
  22. data/spec/factories.rb +6 -0
  23. data/spec/lib/gitara/app_spec.rb +12 -28
  24. data/spec/lib/gitara/dsl_spec.rb +218 -173
  25. data/spec/lib/gitara/node/alternative_spec.rb +15 -0
  26. data/spec/lib/gitara/node/bar/chorded_version_spec.rb +2 -2
  27. data/spec/lib/gitara/node/bar/stanza_version_spec.rb +2 -2
  28. data/spec/lib/gitara/node/bar/voiced_version_spec.rb +2 -2
  29. data/spec/lib/gitara/node/bar_spec.rb +7 -7
  30. data/spec/lib/gitara/node/base/chorded_version_spec.rb +1 -1
  31. data/spec/lib/gitara/node/base/node_version_spec.rb +66 -0
  32. data/spec/lib/gitara/node/base/voiced_version_spec.rb +5 -5
  33. data/spec/lib/gitara/node/base_spec.rb +36 -42
  34. data/spec/lib/gitara/node/chord_set/chorded_version_spec.rb +2 -2
  35. data/spec/lib/gitara/node/chord_set_spec.rb +1 -1
  36. data/spec/lib/gitara/node/note_set_spec.rb +1 -1
  37. data/spec/lib/gitara/node/repeat_spec.rb +15 -0
  38. data/spec/lib/gitara/node/stanza_spec.rb +2 -2
  39. data/spec/lib/gitara/node/tab_spec.rb +6 -6
  40. data/spec/lib/gitara/voice_spec.rb +9 -9
  41. data/spec/lib/gitara_spec.rb +3 -1
  42. data/spec/spec_helper.rb +1 -0
  43. data/spec/support/app_tester.rb +22 -0
  44. metadata +70 -29
  45. data/lib/gitara/is_node_version.rb +0 -23
  46. data/lib/gitara/pow/base.rb +0 -11
  47. data/spec/lib/gitara/is_node_version_spec.rb +0 -58
@@ -0,0 +1,19 @@
1
+ Gitara.define do
2
+ line do
3
+ repeat 4 do
4
+ bar do
5
+ notes "c4 d e f"
6
+ end
7
+ end
8
+
9
+ alternative do
10
+ bar do
11
+ notes "d2 e"
12
+ end
13
+
14
+ bar do
15
+ notes "f2 g"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_runtime_dependency "erubis"
23
23
  s.add_runtime_dependency "linguistics"
24
24
  s.add_runtime_dependency "pow"
25
+ s.add_runtime_dependency "redwood"
25
26
  s.add_runtime_dependency "thor"
26
27
  s.add_runtime_dependency "valuable"
27
28
 
@@ -31,4 +32,6 @@ Gem::Specification.new do |s|
31
32
  s.add_development_dependency "pry"
32
33
  s.add_development_dependency "rb-inotify"
33
34
  s.add_development_dependency "rspec"
35
+ s.add_development_dependency "yard"
36
+ s.add_development_dependency "yard-rspec"
34
37
  end
@@ -2,16 +2,18 @@ require "active_support/inflector"
2
2
  require "erubis"
3
3
  require "linguistics"
4
4
  require "pow"
5
+ require "redwood"
5
6
  require "thor"
6
7
  require "valuable"
7
8
 
8
9
  require "gitara/app"
9
10
  require "gitara/dsl"
10
- require "gitara/is_node_version"
11
11
  require "gitara/node/base"
12
+ require "gitara/node/base/node_version"
12
13
  require "gitara/node/base/chorded_version"
13
14
  require "gitara/node/base/stanza_version"
14
15
  require "gitara/node/base/voiced_version"
16
+ require "gitara/node/alternative"
15
17
  require "gitara/node/bar"
16
18
  require "gitara/node/bar/chorded_version"
17
19
  require "gitara/node/bar/stanza_version"
@@ -20,10 +22,10 @@ require "gitara/node/chord_set"
20
22
  require "gitara/node/chord_set/chorded_version"
21
23
  require "gitara/node/line"
22
24
  require "gitara/node/note_set"
25
+ require "gitara/node/repeat"
23
26
  require "gitara/node/score"
24
27
  require "gitara/node/stanza"
25
28
  require "gitara/node/tab"
26
- require "gitara/pow/base"
27
29
  require "gitara/utilities"
28
30
  require "gitara/version"
29
31
  require "gitara/voice"
@@ -39,7 +41,7 @@ module Gitara
39
41
 
40
42
  def self.render(path, object)
41
43
  template = (Pow!('gitara/template') / "#{path}.erb")
42
- erb = Erubis::Eruby.new(template.read!)
44
+ erb = Erubis::Eruby.new(Utilities.read!(template))
43
45
  erb.evaluate(object)
44
46
  end
45
47
 
@@ -4,8 +4,13 @@ module Gitara
4
4
  class Dsl < Valuable
5
5
  extend DslMacros
6
6
 
7
+ # @macro [attach] has_value
8
+ # @attribute $1
7
9
  has_value :node
8
10
 
11
+ # @macro [attach] can_add_property
12
+ # @method $1(value)
13
+ # Set value as the $1
9
14
  can_add_property :arranger
10
15
  can_add_property :composer
11
16
  can_add_property :instrument
@@ -30,6 +35,10 @@ module Gitara
30
35
  end
31
36
  end
32
37
 
38
+ def alternative(&block)
39
+ add Node::Alternative.new, &block
40
+ end
41
+
33
42
  def bar(*names, &block)
34
43
  add_names :names => names, :node_class => Node::Bar, &block
35
44
  end
@@ -50,6 +59,10 @@ module Gitara
50
59
  node.specified_duration = duration
51
60
  end
52
61
 
62
+ def repeat(value, &block)
63
+ add Node::Repeat.new(:value => value), &block
64
+ end
65
+
53
66
  def score(*names, &block)
54
67
  add_names :names => names, :node_class => Node::Score, &block
55
68
  end
@@ -0,0 +1,14 @@
1
+ module Gitara
2
+ module Node
3
+ class Alternative < Base
4
+ def call_value(node_version)
5
+ alternatives = node_version.definition_children.map do |child|
6
+ "{ #{child.call_value} }"
7
+ end
8
+
9
+ "\\alternative { #{alternatives.join(' ')} }"
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -1,6 +1,8 @@
1
1
  module Gitara
2
2
  module Node
3
3
  class Bar < Base
4
+ # @macro [attach] has_value
5
+ # @attribute $1
4
6
  has_value :specified_duration
5
7
 
6
8
  def duration
@@ -12,7 +14,7 @@ module Gitara
12
14
  end
13
15
 
14
16
  def note_sets
15
- children.select{|child| child.is_a?(Node::NoteSet)}
17
+ definition_children.select{|child| child.is_a?(Node::NoteSet)}
16
18
  end
17
19
 
18
20
  def specified_duration_as_lilypond
@@ -1,31 +1,37 @@
1
1
  module Gitara
2
2
  module Node
3
3
  class Base < Valuable
4
+ include Redwood
5
+
6
+ # @macro [attach] has_value
7
+ # @attribute $1
4
8
  has_value :name
5
9
  has_value :id, :default => 1
6
- has_value :parent
7
10
  has_value :value
8
11
 
9
12
  def add(child)
10
- own_children << child
11
- child.id = own_children.select{|c| c.is_a?(child.class)}.size
12
- child.parent = self
13
+ child.id = children.select{|c| c.is_a?(child.class)}.size + 1
14
+ graft child
15
+ end
16
+
17
+ def ancestor(klass)
18
+ ancestors.detect{|ancestor| ancestor.is_a?(klass)}
13
19
  end
14
20
 
15
- def ancestor(node_class)
16
- self.is_a?(node_class) ? self : self.parent && self.parent.ancestor(node_class)
21
+ def call_value(node_version)
22
+ node_version.call_name
17
23
  end
18
24
 
19
- def children
20
- if own_children.empty?
21
- definition ? definition.own_children : []
25
+ def definition_children
26
+ if leaf?
27
+ definition ? definition.children : []
22
28
  else
23
- own_children
29
+ children
24
30
  end
25
31
  end
26
32
 
27
33
  def children=(values)
28
- own_children.clear
34
+ children.clear
29
35
  values.each do |child|
30
36
  add child
31
37
  end
@@ -39,13 +45,13 @@ module Gitara
39
45
  if self.definition_of?(target)
40
46
  self
41
47
  else
42
- result = parent.own_children.detect{|node| node.definition_of?(target) }
48
+ result = parent.children.detect{|node| node.definition_of?(target) }
43
49
  result ? result : parent.definition(target)
44
50
  end
45
51
  end
46
52
 
47
53
  def definition?
48
- ! own_children.empty? || ! value.nil?
54
+ has_children? || ! value.nil?
49
55
  end
50
56
 
51
57
  def definition_name
@@ -60,11 +66,11 @@ module Gitara
60
66
  end
61
67
 
62
68
  def definitions(klass)
63
- self.is_a?(klass) && self.definition? ? [self] : self.own_children.map{|child| child.definitions(klass) }.flatten
69
+ self.is_a?(klass) && self.definition? ? [self] : self.children.map{|child| child.definitions(klass) }.flatten
64
70
  end
65
71
 
66
72
  def descendants(klass)
67
- self.is_a?(klass) ? [self.definition] : self.children.map{|child| child.descendants(klass) }.flatten
73
+ self.is_a?(klass) ? [self.definition] : self.definition_children.map{|child| child.descendants(klass) }.flatten
68
74
  end
69
75
 
70
76
  def id_as_word
@@ -79,20 +85,12 @@ module Gitara
79
85
  attributes[:name] || "#{parent && parent.name}#{self.class.to_s.split('::').last}#{self.id_as_word}"
80
86
  end
81
87
 
82
- def own_children
83
- @children ||= []
84
- end
85
-
86
- def root
87
- parent.nil? ? self : parent.root
88
- end
89
-
90
88
  def stanza_version
91
89
  self.class::StanzaVersion.new(:node => self)
92
90
  end
93
91
 
94
92
  def value
95
- attributes[:value] ? attributes[:value].gsub('/', "\\") : nil
93
+ attributes[:value].respond_to?(:gsub) ? attributes[:value].gsub('/', "\\") : attributes[:value]
96
94
  end
97
95
 
98
96
  def voiced_as(arg)
@@ -1,10 +1,7 @@
1
1
  module Gitara
2
2
  module Node
3
3
  class Base
4
- class ChordedVersion < Valuable
5
- include IsNodeVersion
6
-
7
- has_value :node
4
+ class ChordedVersion < NodeVersion
8
5
  end
9
6
  end
10
7
  end
@@ -0,0 +1,35 @@
1
+ module Gitara
2
+ module Node
3
+ class Base
4
+ class NodeVersion < Valuable
5
+ # @macro [attach] has_value
6
+ # @attribute $1
7
+ has_value :node
8
+
9
+ def call_name
10
+ "\\#{definition_name}"
11
+ end
12
+
13
+ def call_value
14
+ node.call_value(self)
15
+ end
16
+
17
+ def definition_children
18
+ node.definition_children.map{|child| self.class.new(:node => child)}
19
+ end
20
+
21
+ def definition_name
22
+ "#{prefix}#{node.class.to_s.split('::').last}#{node.definition_name}"
23
+ end
24
+
25
+ def prefix
26
+ self.class.to_s.split('::').last[0].downcase
27
+ end
28
+
29
+ def value
30
+ definition_children.map(&:call_value).join(' ')
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,10 +1,7 @@
1
1
  module Gitara
2
2
  module Node
3
3
  class Base
4
- class StanzaVersion < Valuable
5
- include IsNodeVersion
6
-
7
- has_value :node
4
+ class StanzaVersion < NodeVersion
8
5
  end
9
6
  end
10
7
  end
@@ -1,14 +1,13 @@
1
1
  module Gitara
2
2
  module Node
3
3
  class Base
4
- class VoicedVersion < Valuable
5
- include IsNodeVersion
6
-
7
- has_value :node
4
+ class VoicedVersion < NodeVersion
5
+ # @macro [attach] has_value
6
+ # @attribute $1
8
7
  has_value :voice
9
8
 
10
- def children
11
- node.children.map{|child| child.voiced_as(voice) }
9
+ def definition_children
10
+ node.definition_children.map{|child| child.voiced_as(voice) }
12
11
  end
13
12
 
14
13
  def prefix
@@ -0,0 +1,10 @@
1
+ module Gitara
2
+ module Node
3
+ class Repeat < Base
4
+ def call_value(node_version)
5
+ "\\repeat volta #{value} { #{ node_version.value } }"
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -1,6 +1,8 @@
1
1
  module Gitara
2
2
  module Node
3
3
  class Tab < Base
4
+ # @macro [attach] has_value
5
+ # @attribute $1
4
6
  has_value :arranger
5
7
  has_value :composer
6
8
  has_value :instrument
@@ -11,16 +13,12 @@ module Gitara
11
13
  has_value :title
12
14
  has_value :transposition
13
15
 
14
- def self.parse(text)
15
- Transform.new.apply(Parser.new.parse(text))
16
- end
17
-
18
16
  def max_number_of_voices
19
17
  definitions(Node::Bar).map{|bar| bar.note_sets.size}.max
20
18
  end
21
19
 
22
20
  def playable_child
23
- children.last
21
+ definition_children.last
24
22
  end
25
23
 
26
24
  def voices
@@ -7,6 +7,14 @@ module Gitara
7
7
  def self.inspect_attributes(object, *attributes)
8
8
  "#{object.class}(" + attributes.collect{|a| "#{a}=#{object.send(a).inspect}"}.join(', ') + ")"
9
9
  end
10
+
11
+ def self.read!(pow)
12
+ if pow.exists?
13
+ pow.read
14
+ else
15
+ raise PowError, "#{pow} does not exist"
16
+ end
17
+ end
10
18
  end
11
19
  end
12
20
 
@@ -1,3 +1,3 @@
1
1
  module Gitara
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -1,5 +1,7 @@
1
1
  module Gitara
2
2
  class Voice < Valuable
3
+ # @macro [attach] has_value
4
+ # @attribute $1
3
5
  has_value :id
4
6
  has_value :parent
5
7
 
@@ -2,6 +2,9 @@ FactoryGirl.define do
2
2
  factory :note_set, :class => Node::NoteSet do
3
3
  end
4
4
 
5
+ factory :alternative, :class => Node::Alternative do
6
+ end
7
+
5
8
  factory :app, :class => App do
6
9
  end
7
10
 
@@ -28,6 +31,9 @@ FactoryGirl.define do
28
31
  children [FactoryGirl.build(:bar)]
29
32
  end
30
33
 
34
+ factory :repeat, :class => Node::Repeat do
35
+ end
36
+
31
37
  factory :stanza, :class => Node::Stanza do
32
38
  children [FactoryGirl.build(:line)]
33
39
  end
@@ -1,49 +1,33 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe App do
4
- class AppTest < Valuable
5
- has_value :name
6
-
7
- def run
8
- app = FactoryGirl.build(:app)
9
- app.invoke :export, ["examples/#{name}.rb"], "target-directory" => test_tmp_dir.path, "run-lilypond" => false
10
- (Pow("tmp") / "#{name}.ly").write actual if self.expected != self.actual
11
- end
12
-
13
- def expected
14
- @expected ||= Pow("examples/#{name}.ly").read!.gsub(/\n\s+\n/, "\n")
15
- rescue PowError => e
16
- puts "#{e.message}. Copying actual result..."
17
- Pow("examples/#{name}.ly").write actual
18
- retry
19
- end
20
-
21
- def actual
22
- @actual ||= (test_tmp_dir / "#{name}.ly").read!.gsub(/\n\s+\n/, "\n")
23
- end
24
- end
25
-
26
- describe "export" do
3
+ describe Gitara::App do
4
+ describe "#export" do
27
5
  it "can convert a tab to lilypond" do
28
- app_test = AppTest.new(:name => 'tab')
6
+ app_test = AppTester.new(:name => 'tab')
29
7
  app_test.run
30
8
  app_test.actual.should == app_test.expected
31
9
  end
32
10
 
33
11
  it "can convert a tab with a partial to lilypond" do
34
- app_test = AppTest.new(:name => 'tab-with-partial')
12
+ app_test = AppTester.new(:name => 'tab-with-partial')
35
13
  app_test.run
36
14
  app_test.actual.should == app_test.expected
37
15
  end
38
16
 
39
17
  it "can convert a tab with alternate tuning to lilypond" do
40
- app_test = AppTest.new(:name => 'tab-with-alternate-tuning')
18
+ app_test = AppTester.new(:name => 'tab-with-alternate-tuning')
41
19
  app_test.run
42
20
  app_test.actual.should == app_test.expected
43
21
  end
44
22
 
45
23
  it "can convert a tab with a specified key signature to lilypond" do
46
- app_test = AppTest.new(:name => 'tab-with-key-signature')
24
+ app_test = AppTester.new(:name => 'tab-with-key-signature')
25
+ app_test.run
26
+ app_test.actual.should == app_test.expected
27
+ end
28
+
29
+ it "can convert a tab with repeats to lilypond" do
30
+ app_test = AppTester.new(:name => 'tab-with-repeats')
47
31
  app_test.run
48
32
  app_test.actual.should == app_test.expected
49
33
  end