musicality 0.10.1 → 0.11.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 +4 -4
- data/ChangeLog.md +13 -3
- data/README.md +8 -8
- data/bin/auditions +241 -0
- data/bin/collidify +4 -2
- data/bin/musicality +13 -2
- data/examples/composition/auto_counterpoint.rb +4 -4
- data/examples/composition/part_generator.rb +6 -6
- data/examples/composition/scale_exercise.rb +5 -5
- data/examples/notation/scores.rb +2 -2
- data/examples/notation/twinkle.rb +6 -6
- data/examples/notation/twinkle.score +3 -3
- data/lib/musicality.rb +6 -4
- data/lib/musicality/composition/dsl/part_methods.rb +12 -0
- data/lib/musicality/composition/dsl/score_dsl.rb +4 -4
- data/lib/musicality/composition/dsl/score_methods.rb +8 -2
- data/lib/musicality/notation/model/audition.rb +16 -0
- data/lib/musicality/notation/model/score.rb +31 -30
- data/lib/musicality/performance/supercollider/conductor.rb +2 -2
- data/lib/musicality/performance/supercollider/synthdefs.rb +30 -29
- data/lib/musicality/project/auditions_task.rb +28 -0
- data/lib/musicality/project/create_tasks.rb +15 -9
- data/lib/musicality/project/file_cleaner.rb +22 -5
- data/lib/musicality/project/file_raker.rb +29 -21
- data/lib/musicality/project/project.rb +218 -32
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +6 -4
- data/spec/composition/dsl/part_methods_spec.rb +24 -0
- data/spec/notation/conversion/score_conversion_spec.rb +2 -1
- data/spec/notation/conversion/score_converter_spec.rb +23 -23
- data/spec/notation/model/score_spec.rb +66 -46
- data/spec/performance/conversion/score_collator_spec.rb +29 -29
- data/spec/performance/midi/score_sequencing_spec.rb +5 -5
- metadata +10 -8
- data/lib/musicality/project/load_config.rb +0 -58
@@ -0,0 +1,28 @@
|
|
1
|
+
module Musicality
|
2
|
+
module Tasks
|
3
|
+
|
4
|
+
class Auditions < Rake::TaskLib
|
5
|
+
attr_reader :auditions_dirs
|
6
|
+
|
7
|
+
TEMPO_SAMPLE_RATE = 200
|
8
|
+
AUDITIONS_DIR = "auditions"
|
9
|
+
AUDITIONS_EXT = ".auditions"
|
10
|
+
|
11
|
+
def initialize yaml_filelist, audio_format = nil
|
12
|
+
@auditions_dirs = yaml_filelist.pathmap("%d/#{AUDITIONS_DIR}")
|
13
|
+
@auditions_dirs.each { |auditions_dir| directory auditions_dir }
|
14
|
+
|
15
|
+
format_flag = audio_format.nil? ? "" : "--format=#{audio_format}"
|
16
|
+
subtask = audio_format.nil? ? "" : ":#{audio_format}"
|
17
|
+
|
18
|
+
task "auditions#{subtask}" => yaml_filelist + @auditions_dirs do
|
19
|
+
yaml_filelist.each_with_index do |yaml_fname,i|
|
20
|
+
auditions_dir = @auditions_dirs[i]
|
21
|
+
`auditions #{yaml_fname} --outdir="#{auditions_dir}" #{format_flag}`
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -1,31 +1,37 @@
|
|
1
1
|
module Musicality
|
2
|
+
class Project
|
2
3
|
|
3
|
-
class Project
|
4
4
|
def self.create_tasks config
|
5
|
-
score_files = Rake::FileList[
|
6
|
-
|
5
|
+
score_files = Rake::FileList[File.join(SCORES_DIR,"*"+SCORE_EXT)]
|
6
|
+
|
7
7
|
yaml_task = Tasks::FileRaker::YAML.new(score_files)
|
8
|
-
|
8
|
+
|
9
9
|
tempo_sample_rate = config[:tempo_sample_rate]
|
10
10
|
lilypond_task = Tasks::FileRaker::LilyPond.new(yaml_task.files)
|
11
11
|
midi_task = Tasks::FileRaker::MIDI.new(yaml_task.files, tempo_sample_rate)
|
12
12
|
supercollider_task = Tasks::FileRaker::SuperCollider.new(yaml_task.files, tempo_sample_rate)
|
13
|
-
|
13
|
+
|
14
14
|
sample_rate, sample_format = config[:audio_sample_rate], config[:audio_sample_format]
|
15
15
|
wav_task = Tasks::FileRaker::Audio.new(supercollider_task.files, :wav, sample_rate, sample_format)
|
16
16
|
aiff_task = Tasks::FileRaker::Audio.new(supercollider_task.files, :aiff, sample_rate, sample_format)
|
17
17
|
flac_task = Tasks::FileRaker::Audio.new(supercollider_task.files, :flac, sample_rate, sample_format)
|
18
|
-
|
18
|
+
|
19
19
|
pdf_task = Tasks::FileRaker::Visual.new(lilypond_task.files, :pdf)
|
20
20
|
png_task = Tasks::FileRaker::Visual.new(lilypond_task.files, :png)
|
21
21
|
ps_task = Tasks::FileRaker::Visual.new(lilypond_task.files, :ps)
|
22
22
|
|
23
|
+
auditions_default_task = Tasks::Auditions.new yaml_task.files
|
24
|
+
auditions_flac_task = Tasks::Auditions.new yaml_task.files, "flac"
|
25
|
+
auditions_wav_task = Tasks::Auditions.new yaml_task.files, "wav"
|
26
|
+
auditions_aiff_task = Tasks::Auditions.new yaml_task.files, "aiff"
|
27
|
+
|
23
28
|
outfiles = (
|
24
|
-
yaml_task.files + lilypond_task.files + midi_task.files + supercollider_task.files +
|
25
|
-
pdf_task.files + png_task.files + ps_task.files +
|
29
|
+
yaml_task.files + lilypond_task.files + midi_task.files + supercollider_task.files +
|
30
|
+
pdf_task.files + png_task.files + ps_task.files +
|
26
31
|
wav_task.files + aiff_task.files + flac_task.files
|
27
32
|
).select {|fname| File.exists? fname }
|
28
|
-
|
33
|
+
outdirs = auditions_default_task.auditions_dirs + yaml_task.subdirs + [Project::OUT_DIR]
|
34
|
+
clean_task = Tasks::FileCleaner.new(outfiles, outdirs)
|
29
35
|
end
|
30
36
|
end
|
31
37
|
|
@@ -1,19 +1,36 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
1
3
|
module Musicality
|
2
4
|
module Tasks
|
3
5
|
|
4
6
|
class FileCleaner < Rake::TaskLib
|
5
|
-
def initialize
|
7
|
+
def initialize files, dirs
|
6
8
|
task :clean do
|
7
|
-
if
|
8
|
-
puts "Deleting
|
9
|
-
|
9
|
+
if files.any?
|
10
|
+
puts "Deleting files:"
|
11
|
+
files.each do |fname|
|
10
12
|
puts " " + fname
|
11
13
|
File.delete fname
|
12
14
|
end
|
13
15
|
end
|
16
|
+
|
17
|
+
existing_dirs = dirs.select {|dir| Dir.exist?(dir) }
|
18
|
+
|
19
|
+
if existing_dirs.any?
|
20
|
+
puts "Deleting dirs:"
|
21
|
+
existing_dirs.each do |dirname|
|
22
|
+
puts " " + dirname
|
23
|
+
begin
|
24
|
+
FileUtils::rm Dir.glob(File.join(dirname, "*"))
|
25
|
+
FileUtils::rmdir dirname
|
26
|
+
rescue => e
|
27
|
+
puts "Error while trying to delete #{dirname}: #{e}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
14
31
|
end
|
15
32
|
end
|
16
33
|
end
|
17
34
|
|
18
35
|
end
|
19
|
-
end
|
36
|
+
end
|
@@ -2,26 +2,34 @@ module Musicality
|
|
2
2
|
module Tasks
|
3
3
|
|
4
4
|
class FileRaker < Rake::TaskLib
|
5
|
-
attr_reader :files, :task_name, :file_ext
|
6
|
-
|
5
|
+
attr_reader :files, :task_name, :file_ext, :subdirs
|
6
|
+
|
7
7
|
def initialize parent_filelist, task_name, file_ext, &rule_block
|
8
8
|
raise ArgumentError, "parent filelist is empty" if parent_filelist.empty?
|
9
9
|
raise ArgumentError, "no rule block given" unless block_given?
|
10
|
-
|
11
|
-
@task_name, @file_ext = task_name, file_ext
|
12
|
-
@files = parent_filelist.ext(file_ext)
|
13
|
-
|
14
|
-
task task_name => @files
|
15
|
-
|
10
|
+
|
16
11
|
parent_exts = parent_filelist.map {|str| File.extname(str) }.uniq
|
17
12
|
raise ArgumentError, "multiple file extensions in parent filelist: #{parent_filelist}" unless parent_exts.one?
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
|
14
|
+
@task_name, @file_ext = task_name, file_ext
|
15
|
+
@subdirs = parent_filelist.pathmap("#{Project::OUT_DIR}/%n")
|
16
|
+
@files = parent_filelist.pathmap("#{Project::OUT_DIR}/%n/%n#{file_ext}")
|
17
|
+
|
18
|
+
directory Project::OUT_DIR
|
19
|
+
@subdirs.each { |subdir| directory subdir }
|
20
|
+
task task_name => [Project::OUT_DIR] + @subdirs + @files
|
21
|
+
|
22
|
+
find_parent_file = lambda do |f|
|
23
|
+
parent_filelist.detect do |f2|
|
24
|
+
File.basename(f2.ext("")) == File.basename(f.ext(""))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rule file_ext => find_parent_file do |t|
|
21
29
|
rule_block.call(t)
|
22
30
|
end
|
23
31
|
end
|
24
|
-
|
32
|
+
|
25
33
|
class YAML < FileRaker
|
26
34
|
def initialize score_files
|
27
35
|
super(score_files, :yaml, ".yml") do |t|
|
@@ -31,7 +39,7 @@ class FileRaker < Rake::TaskLib
|
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
34
|
-
|
42
|
+
|
35
43
|
class LilyPond < FileRaker
|
36
44
|
def initialize yaml_files
|
37
45
|
super(yaml_files, :lilypond, ".ly") do |t|
|
@@ -39,7 +47,7 @@ class FileRaker < Rake::TaskLib
|
|
39
47
|
end
|
40
48
|
end
|
41
49
|
end
|
42
|
-
|
50
|
+
|
43
51
|
class MIDI < FileRaker
|
44
52
|
def initialize yaml_files, tempo_sample_rate
|
45
53
|
super(yaml_files, :midi, ".mid") do |t|
|
@@ -47,7 +55,7 @@ class FileRaker < Rake::TaskLib
|
|
47
55
|
end
|
48
56
|
end
|
49
57
|
end
|
50
|
-
|
58
|
+
|
51
59
|
class SuperCollider < FileRaker
|
52
60
|
def initialize yaml_files, tempo_sample_rate
|
53
61
|
super(yaml_files, :supercollider, ".osc") do |t|
|
@@ -55,7 +63,7 @@ class FileRaker < Rake::TaskLib
|
|
55
63
|
end
|
56
64
|
end
|
57
65
|
end
|
58
|
-
|
66
|
+
|
59
67
|
class Audio < FileRaker
|
60
68
|
def check_sample_format audio_file_type, sample_format
|
61
69
|
combination_okay = case audio_file_type
|
@@ -64,7 +72,7 @@ class FileRaker < Rake::TaskLib
|
|
64
72
|
when :flac
|
65
73
|
!["int32","float","mulaw","alaw"].include?(sample_format)
|
66
74
|
else
|
67
|
-
true
|
75
|
+
true
|
68
76
|
end
|
69
77
|
|
70
78
|
unless combination_okay
|
@@ -78,7 +86,7 @@ class FileRaker < Rake::TaskLib
|
|
78
86
|
|
79
87
|
osc_fpath = t.sources[0]
|
80
88
|
out_fpath = File.join(File.dirname(osc_fpath), File.basename(osc_fpath, File.extname(osc_fpath)) + ".#{audio_file_type}")
|
81
|
-
|
89
|
+
|
82
90
|
cmd_line = "scsynth -N \"#{osc_fpath}\" _ \"#{out_fpath}\" #{sample_rate} #{audio_file_type} #{sample_format}"
|
83
91
|
IO.popen(cmd_line) do |pipe|
|
84
92
|
while response = pipe.gets
|
@@ -93,13 +101,13 @@ class FileRaker < Rake::TaskLib
|
|
93
101
|
end
|
94
102
|
end
|
95
103
|
end
|
96
|
-
|
104
|
+
|
97
105
|
class Visual < FileRaker
|
98
106
|
def initialize lilypond_files, visual_file_type
|
99
107
|
super(lilypond_files, visual_file_type, ".#{visual_file_type}") do |t|
|
100
108
|
ly_fpath = t.sources[0]
|
101
109
|
out_dir = File.dirname(ly_fpath)
|
102
|
-
|
110
|
+
|
103
111
|
sh "lilypond --output=\"#{out_dir}\" \"#{ly_fpath}\" --#{visual_file_type}"
|
104
112
|
end
|
105
113
|
end
|
@@ -107,4 +115,4 @@ class FileRaker < Rake::TaskLib
|
|
107
115
|
end
|
108
116
|
|
109
117
|
end
|
110
|
-
end
|
118
|
+
end
|
@@ -1,25 +1,71 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
3
|
class Project
|
4
|
+
CONFIG_FILE_NAME = "config.yml"
|
5
|
+
SCORES_DIR = "scores"
|
6
|
+
SCORE_EXT = ".score"
|
7
|
+
OUT_DIR = "output"
|
8
|
+
SAMPLE_FORMATS = ["int8", "int16", "int24", "int32", "mulaw", "alaw", "float"]
|
9
|
+
DEFAULT_CONFIG = {
|
10
|
+
:tempo_sample_rate => 200,
|
11
|
+
:audio_sample_rate => 44100,
|
12
|
+
:audio_sample_format => "int16"
|
13
|
+
}
|
14
|
+
GEM_MUSICALITY = "gem 'musicality', '~> #{VERSION}'"
|
4
15
|
USEFUL_MODULES = ['Musicality','Pitches','Meters','Keys','Articulations','Dynamics']
|
5
16
|
|
6
|
-
|
17
|
+
class ConfigError < RuntimeError
|
18
|
+
end
|
19
|
+
|
7
20
|
def initialize dest_dir
|
8
|
-
|
21
|
+
Project.create_project_dir_if_needed(dest_dir)
|
22
|
+
Project.create_scores_dir_if_needed(dest_dir)
|
23
|
+
Project.update(dest_dir)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.update dest_dir
|
27
|
+
if File.exists?(gemfile_path(dest_dir))
|
28
|
+
puts "Updating Gemfile"
|
29
|
+
update_gemfile(dest_dir)
|
30
|
+
else
|
31
|
+
puts "Creating Gemfile"
|
32
|
+
create_gemfile(dest_dir)
|
33
|
+
end
|
34
|
+
|
35
|
+
if File.exists?(rakefile_path(dest_dir))
|
36
|
+
puts "Updating Rakefile"
|
37
|
+
update_rakefile(dest_dir)
|
38
|
+
else
|
39
|
+
puts "Creating Rakefile"
|
40
|
+
create_rakefile(dest_dir)
|
41
|
+
end
|
9
42
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
43
|
+
if File.exists?(config_path(dest_dir))
|
44
|
+
puts "Updating config.yml"
|
45
|
+
update_config(dest_dir)
|
46
|
+
else
|
47
|
+
puts "Creating config.yml"
|
48
|
+
create_config(dest_dir)
|
49
|
+
end
|
15
50
|
end
|
16
51
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
52
|
+
def self.config_path(dest_dir)
|
53
|
+
File.join(dest_dir,"config.yml")
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.gemfile_path(dest_dir)
|
57
|
+
File.join(dest_dir,"Gemfile")
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.rakefile_path(dest_dir)
|
61
|
+
File.join(dest_dir,"Rakefile")
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.create_project_dir_if_needed(dest_dir)
|
65
|
+
if Dir.exists?(dest_dir)
|
66
|
+
puts "Project directory already exists"
|
22
67
|
else
|
68
|
+
puts "Creating project directory #{dest_dir}"
|
23
69
|
Dir.mkdir(dest_dir)
|
24
70
|
unless Dir.exists?(dest_dir)
|
25
71
|
raise "directory #{dest_dir} could not be created"
|
@@ -27,38 +73,178 @@ class Project
|
|
27
73
|
end
|
28
74
|
end
|
29
75
|
|
30
|
-
def
|
76
|
+
def self.create_scores_dir_if_needed(dest_dir, scores_dir = Project::SCORES_DIR)
|
77
|
+
scores_dir = File.join(dest_dir, scores_dir)
|
78
|
+
if Dir.exists? scores_dir
|
79
|
+
puts "Scores directory already exists"
|
80
|
+
else
|
81
|
+
puts "Creating scores directory #{scores_dir}"
|
82
|
+
Dir.mkdir(scores_dir)
|
83
|
+
unless Dir.exists?(scores_dir)
|
84
|
+
raise "directory #{scores_dir} could not be created"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Gemfile
|
91
|
+
#
|
92
|
+
|
93
|
+
def self.create_gemfile(dest_dir)
|
31
94
|
gemfile_path = File.join(dest_dir,"Gemfile")
|
32
|
-
File.
|
33
|
-
|
34
|
-
|
95
|
+
File.new(gemfile_path(dest_dir),"w")
|
96
|
+
update_gemfile(dest_dir)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.update_gemfile(dest_dir)
|
100
|
+
pre_lines = []
|
101
|
+
lines = File.readlines(gemfile_path(dest_dir)).map {|l| l.chomp }
|
102
|
+
|
103
|
+
if line = lines.find {|x| x =~ /source/ }
|
104
|
+
delete_empty_lines_around lines, line
|
105
|
+
pre_lines.push lines.delete(line)
|
106
|
+
else
|
107
|
+
pre_lines.push("source :rubygems")
|
108
|
+
end
|
109
|
+
|
110
|
+
if line = lines.find {|x| x =~ /gem/ && x =~ /musicality/ }
|
111
|
+
delete_empty_lines_around lines, line
|
112
|
+
lines.delete(line)
|
113
|
+
end
|
114
|
+
pre_lines.push GEM_MUSICALITY
|
115
|
+
|
116
|
+
File.open(gemfile_path(dest_dir),"w") do |f|
|
117
|
+
f.puts pre_lines
|
118
|
+
if lines.any?
|
119
|
+
f.puts [""] + lines
|
120
|
+
end
|
35
121
|
end
|
36
122
|
end
|
37
123
|
|
38
|
-
|
124
|
+
#
|
125
|
+
# Rakefile
|
126
|
+
#
|
127
|
+
|
128
|
+
def self.create_rakefile(dest_dir)
|
39
129
|
rakefile_path = File.join(dest_dir,"Rakefile")
|
40
|
-
File.
|
41
|
-
|
42
|
-
|
43
|
-
|
130
|
+
File.new(rakefile_path(dest_dir),"w")
|
131
|
+
update_rakefile(dest_dir)
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.update_rakefile(dest_dir)
|
135
|
+
pre_lines = []
|
136
|
+
lines = File.readlines(rakefile_path(dest_dir)).map {|l| l.chomp }
|
137
|
+
|
138
|
+
if line = lines.find {|x| x =~ /^[\s]*require[\s]+[\'\"]musicality[\'\"]/}
|
139
|
+
delete_empty_lines_around lines, line
|
140
|
+
pre_lines.push lines.delete(line)
|
141
|
+
else
|
142
|
+
pre_lines.push "require 'musicality'"
|
143
|
+
end
|
144
|
+
pre_lines.push ""
|
145
|
+
|
146
|
+
USEFUL_MODULES.each do |module_name|
|
147
|
+
if line = lines.find {|x| x =~ /^[\s]*include[\s]+#{module_name}/}
|
148
|
+
delete_empty_lines_around lines, line
|
149
|
+
pre_lines.push lines.delete(line)
|
150
|
+
else
|
151
|
+
pre_lines.push "include #{module_name}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
pre_lines.push ""
|
156
|
+
if line = lines.find {|x| x =~ /Project\.load_config/ }
|
157
|
+
delete_empty_lines_around lines, line
|
158
|
+
pre_lines.push lines.delete(line)
|
159
|
+
else
|
160
|
+
pre_lines.push "config = Project.load_config(File.dirname(__FILE__))"
|
161
|
+
end
|
162
|
+
|
163
|
+
if line = lines.find {|x| x =~ /Project\.create_tasks/ }
|
164
|
+
delete_empty_lines_around lines, line
|
165
|
+
pre_lines.push lines.delete(line)
|
166
|
+
else
|
167
|
+
pre_lines.push "Project.create_tasks(config)"
|
168
|
+
end
|
169
|
+
|
170
|
+
File.open(rakefile_path(dest_dir),"w") do |f|
|
171
|
+
f.puts pre_lines
|
172
|
+
if lines.any?
|
173
|
+
f.puts [""] + lines
|
44
174
|
end
|
45
|
-
f.puts
|
46
|
-
f.puts("config = Project.load_config(File.dirname(__FILE__))")
|
47
|
-
f.puts("Project.create_tasks(config)")
|
48
175
|
end
|
49
176
|
end
|
50
177
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
178
|
+
#
|
179
|
+
# config.yml
|
180
|
+
#
|
181
|
+
|
182
|
+
def self.check_config config
|
183
|
+
config.each do |k,v|
|
184
|
+
case k
|
185
|
+
when :audio_sample_format
|
186
|
+
raise ConfigError, "#{k} => #{v} is not allowed" unless SAMPLE_FORMATS.include?(v)
|
187
|
+
when :tempo_sample_rate, :audio_sample_rate
|
188
|
+
raise ConfigError, "#{k} => #{v} is not positive" unless v > 0
|
189
|
+
end
|
55
190
|
end
|
56
191
|
end
|
57
192
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
193
|
+
def self.load_config project_root_dir
|
194
|
+
globabl_config_path = File.join(project_root_dir,CONFIG_FILE_NAME)
|
195
|
+
|
196
|
+
config = if File.exists? globabl_config_path
|
197
|
+
global_config = YAML.load(File.read(globabl_config_path))
|
198
|
+
DEFAULT_CONFIG.merge global_config
|
199
|
+
else
|
200
|
+
DEFAULT_CONFIG
|
201
|
+
end
|
202
|
+
|
203
|
+
# overrides from ENV
|
204
|
+
config.keys.each do |k|
|
205
|
+
k_str = k.to_s
|
206
|
+
if ENV.has_key? k_str
|
207
|
+
case k
|
208
|
+
when :tempo_sample_rate, :audio_sample_rate
|
209
|
+
config[k] = ENV[k_str].to_i
|
210
|
+
else
|
211
|
+
config[k] = ENV[k_str]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
check_config config
|
217
|
+
return config
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.create_config(dest_dir, config = Project::DEFAULT_CONFIG)
|
221
|
+
File.open(config_path(dest_dir),"w") do |f|
|
222
|
+
f.write(config.to_yaml)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.update_config(dest_dir)
|
227
|
+
config = Project.load_config(dest_dir)
|
228
|
+
config = Project::DEFAULT_CONFIG.merge(config)
|
229
|
+
create_config(dest_dir, config)
|
230
|
+
end
|
231
|
+
|
232
|
+
private
|
233
|
+
|
234
|
+
def self.delete_empty_lines_around lines, line
|
235
|
+
# delete lines before
|
236
|
+
i = lines.index(line)-1
|
237
|
+
while (i >= 0) && lines[i].empty?
|
238
|
+
lines.delete_at i
|
239
|
+
i -= 1
|
240
|
+
end
|
241
|
+
|
242
|
+
# delete lines after
|
243
|
+
i = lines.index(line)+1
|
244
|
+
while (i < lines.size) && lines[i].empty?
|
245
|
+
lines.delete_at i
|
246
|
+
end
|
61
247
|
end
|
62
248
|
end
|
63
249
|
|
64
|
-
end
|
250
|
+
end
|