milkode 0.9.2 → 0.9.3

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.
@@ -22,7 +22,7 @@ set :haml, :format => :html5
22
22
 
23
23
  get '/' do
24
24
  @setting = WebSetting.new
25
- @version = "0.9.2"
25
+ @version = "0.9.3"
26
26
  @package_num = Database.instance.yaml_package_num
27
27
  @file_num = Database.instance.totalRecords
28
28
  @package_list = PackageList.new(Database.instance.grndb)
@@ -62,6 +62,20 @@ post '/search*' do
62
62
  end
63
63
  end
64
64
 
65
+ post '/command' do
66
+ case params[:kind]
67
+ when 'update'
68
+ before = Time.now
69
+ if (params[:name] == '')
70
+ result = Database.instance.update_all
71
+ update_result_str(result, before)
72
+ else
73
+ result = Database.instance.update(params[:name])
74
+ update_result_str(result, before)
75
+ end
76
+ end
77
+ end
78
+
65
79
  get '/home*' do |path|
66
80
  before = Time.now
67
81
  path = path.sub(/^\//, "")
@@ -158,11 +172,35 @@ EOF
158
172
  def create_headmenu(path, query, flistpath = '')
159
173
  href = Mkurl.new('/home/' + path, params).inherit_query_shead
160
174
  flist = File.join("/home/#{path}", flistpath)
175
+
176
+ package_name = ""
177
+ modal_body = "全てのパッケージを更新しますか?"
178
+
179
+ if (path != "")
180
+ package_name = path.split('/')[0]
181
+ modal_body = "#{package_name} を更新しますか?"
182
+ end
183
+
161
184
  <<EOF
162
- #{headicon('go-home-5.png')} <a href="/home" class="headmenu">全てのパッケージ</a>
185
+ #{headicon('go-home-5.png')} <a href="/home" class="headmenu">ホーム</a>
163
186
  #{headicon('document-new-4.png')} <a href="#{href}" class="headmenu" onclick="window.open('#{href}'); return false;">新しい検索</a>
164
187
  #{headicon('directory.png')} <a href="#{flist}" class="headmenu">ディレクトリ</a>
188
+ #{headicon('view-refresh-4.png')} <a href="#updateModal" class="headmenu" data-toggle="modal">パッケージを更新</a>
165
189
  #{headicon('help.png')} <a href="/help" class="headmenu">ヘルプ</a>
190
+
191
+ <div id="updateModal" class="modal hide fade">
192
+ <div class="modal-header">
193
+ <a href="#" class="close" data-dismiss="modal">&times;</a>
194
+ <h3>パッケージを更新</h3>
195
+ </div>
196
+ <div class="modal-body">
197
+ <h4>#{modal_body}</h4>
198
+ </div>
199
+ <div class="modal-footer">
200
+ <a href="#" id="updateCancel" class="btn" data-dismiss="modal">Cancel</a>
201
+ <a href="#" id="updateOk" class="btn btn-primary" data-loading-text="Updating..." milkode-package-name="#{package_name}"">OK</a>
202
+ </div>
203
+ </div>
166
204
  EOF
167
205
  end
168
206
 
@@ -224,6 +262,15 @@ EOF
224
262
  def filelist_title(path)
225
263
  (path == "") ? "Package List" : path
226
264
  end
265
+
266
+ def update_result_str(result, before)
267
+ r = []
268
+ r << "#{result.package_count} packages" if result.package_count > 1
269
+ r << "#{result.file_count} records"
270
+ r << "#{result.add_count} add"
271
+ r << "#{result.update_count} update"
272
+ "#{r.join(', ')} (#{Time.now - before} sec)"
273
+ end
227
274
  end
228
275
 
229
276
  class Array
@@ -13,6 +13,7 @@ require 'milkode/common/dbdir'
13
13
  require 'milkode/cdstk/yaml_file_wrapper'
14
14
  require 'milkode/database/groonga_database'
15
15
  require 'milkode/common/util'
16
+ require 'milkode/database/updater'
16
17
  include Milkode
17
18
 
18
19
  module Milkode
@@ -168,6 +169,20 @@ module Milkode
168
169
  package, restpath = Util::divide_shortpath(path)
169
170
  @grndb.packages.touch_if(package, :viewtime) if package
170
171
  end
172
+
173
+ def update(name)
174
+ result = Updater::ResultAccumulator.new
175
+ result << update_in(yaml_load.find_name(name))
176
+ result
177
+ end
178
+
179
+ def update_all
180
+ result = Updater::ResultAccumulator.new
181
+ yaml_load.contents.each do |package|
182
+ result << update_in(package)
183
+ end
184
+ result
185
+ end
171
186
 
172
187
  private
173
188
 
@@ -175,5 +190,14 @@ module Milkode
175
190
  YamlFileWrapper.load_if(Database.dbdir)
176
191
  end
177
192
 
193
+ def update_in(package)
194
+ updater = Updater.new(@grndb, package.name)
195
+ updater.set_package_ignore IgnoreSetting.new("/", package.ignore)
196
+ updater.enable_no_auto_ignore if package.options[:no_auto_ignore]
197
+ updater.enable_update_with_git_pull if package.options[:update_with_git_pull]
198
+ updater.exec
199
+ updater.result
200
+ end
201
+
178
202
  end
179
203
  end
@@ -84,5 +84,30 @@ $(document).ready(function(){
84
84
  selectedList: 1,
85
85
  height: 350
86
86
  }).multiselectfilter();
87
+
88
+ $("#updateOk").click(function (e) {
89
+ update_package($("#updateOk").attr("milkode-package-name"));
90
+ return false;
91
+ });
87
92
  });
88
93
 
94
+ function update_package(package_name)
95
+ {
96
+ // click button
97
+ $("#updateModal .modal-body").html("<h4>更新中... <img src='/images/waiting.gif'/></h4>");
98
+ $("#updateCancel").addClass("hide");
99
+ $("#updateOk").button('loading').off('click');
100
+
101
+ // update end
102
+ $.post(
103
+ '/command',
104
+ {
105
+ kind: 'update',
106
+ name: package_name
107
+ },
108
+ function (data) {
109
+ $("#updateModal .modal-body").html("<h4>実行結果</h4>" + "<p>" + data + "</p>");
110
+ $("#updateOk").button('reset').attr("data-dismiss", "modal").text("Close").on('click', function () { location.reload(); });
111
+ }
112
+ );
113
+ }
@@ -20,6 +20,7 @@
20
20
  %script(type='text/javascript' src='/js/jquery-ui-1.8.22.custom.min.js')
21
21
  %script(type='text/javascript' src='/js/jquery.multiselect.min.js')
22
22
  %script(type='text/javascript' src='/js/jquery.multiselect.filter.min.js')
23
+ %script(type='text/javascript' src='/js/bootstrap.min.js')
23
24
  %script(type='text/javascript' src='/js/milkode.js')
24
25
 
25
26
  -# GoogleAnalyticsを使いたい場合はここにコードを挿入して下さい。
@@ -32,7 +32,7 @@ Samples:
32
32
  milk add git://github.com/ongaeshi/milkode.git
33
33
  EOF
34
34
  option :ignore, :type => :array, :aliases => '-i', :desc => 'Ignore path.'
35
- option :no_auto_ignore, :type => :boolean, :desc => 'Disable auto ignore (.gitignore).'
35
+ option :no_auto_ignore, :type => :boolean, :aliases => '-n', :desc => 'Disable auto ignore (.gitignore).'
36
36
  option :verbose, :type => :boolean, :aliases => '-v', :desc => 'Be verbose.'
37
37
 
38
38
  def add(*args)
@@ -108,9 +108,15 @@ EOF
108
108
  cdstk.mcd(options)
109
109
  end
110
110
 
111
- desc "info", "Information of milkode status"
112
- def info
113
- cdstk.info
111
+ desc "info [package]", "Display package information"
112
+ option :all, :type => :boolean, :aliases => '-a', :desc => 'Display all packages'
113
+ option :detail, :type => :boolean, :aliases => '-d', :desc => 'Detail format'
114
+ option :table, :type => :boolean, :aliases => '-t', :desc => 'Table format'
115
+ option :breakdown, :type => :boolean, :aliases => '-b', :desc => 'Breakdown format'
116
+ option :unknown, :type => :boolean, :aliases => '-u', :desc => 'Display unknown files'
117
+
118
+ def info(*args)
119
+ cdstk.info(args_or_pipe(args, $stdin), options)
114
120
  end
115
121
 
116
122
  desc "ignore [path ...]", "Ignore a file or directory"
@@ -169,10 +175,16 @@ EOF
169
175
  $stdout.puts <<EOF
170
176
  Gitomb https://github.com/tomykaira/gitomb
171
177
  redmine_milkode https://github.com/suer/redmine_milkode
178
+ Milkode_Sublime https://github.com/tsurushuu/Milkode_Sublime
172
179
  emacs-milkode https://github.com/ongaeshi/emacs-milkode
173
180
  EOF
174
181
  end
175
182
 
183
+ desc "files", "Display package files"
184
+ def files(*args)
185
+ cdstk.files(args)
186
+ end
187
+
176
188
  # --------------------------------------------------------------------------
177
189
 
178
190
  no_tasks do
@@ -208,5 +220,16 @@ EOF
208
220
  end
209
221
  end
210
222
 
223
+ # 引数が空の場合はパイプ(標準入力)を受け取る
224
+ def args_or_pipe(args, stdin)
225
+ if !args.empty?
226
+ args
227
+ elsif File.pipe?(stdin)
228
+ stdin.readlines.map{|v| v.chomp}
229
+ else
230
+ []
231
+ end
232
+ end
233
+
211
234
  end
212
235
  end
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module GrenFileTest
4
- IGNORE_FILE = /(\A#.*#\Z)|(~\Z)|(\A\.#)|(\.d\Z)|(\.map\Z)|(\.MAP\Z)/
4
+ IGNORE_FILE = /(\A#.*#\Z)|(~\Z)|(\A\.#)|(\.d\Z)|(\.map\Z)|(\.MAP\Z)|(\.xbm\Z)|(\.ppm\Z)|(\.ai\Z)|(\.png\Z)|(\.webarchive\Z)/
5
5
  IGNORE_DIR = /(\A\.svn\Z)|(\A\.git\Z)|(\ACVS\Z)/
6
6
 
7
7
  def self.ignoreDir?(fpath)
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief Programming Language Detector
5
+ # @author ongaeshi
6
+ # @date 2012/09/29
7
+
8
+ module Milkode
9
+ class PlangDetector
10
+ LANGUAGES =
11
+ [
12
+ # high priority
13
+ { :name => 'README' , :filepatterns => ['README', 'readme'] },
14
+
15
+ # normal priority
16
+ { :name => 'ActionScript' , :suffixs => ['as'] },
17
+ { :name => 'Autotools' , :suffixs => ['am', 'in'] },
18
+ { :name => 'AWK' , :suffixs => ['awk'] },
19
+ { :name => 'Batch File' , :suffixs => ['bat'] },
20
+ { :name => 'Bundler' , :filenames => ['Gemfile', 'Gemfile.lock'] },
21
+ { :name => 'C' , :suffixs => ['c', 'h'] },
22
+ { :name => 'C#' , :suffixs => ['cs'] },
23
+ { :name => 'C++' , :suffixs => ['cc', 'cpp', 'hpp'] },
24
+ { :name => 'CGI' , :suffixs => ['cgi'] },
25
+ { :name => 'ChangeLog' , :filenames => ['ChangeLog'] },
26
+ { :name => 'Common Lisp' , :suffixs => ['cl'] },
27
+ { :name => 'CSS' , :suffixs => ['css'] },
28
+ { :name => 'CSV' , :suffixs => ['csv'] },
29
+ { :name => 'Diff' , :suffixs => ['diff'] },
30
+ { :name => 'Emacs Lisp' , :suffixs => ['el'] },
31
+ { :name => 'Erlang' , :suffixs => ['erl'] },
32
+ { :name => 'eRuby' , :suffixs => ['erb', 'rhtml'] },
33
+ { :name => 'gitignore' , :filenames => ['.gitignore'] },
34
+ { :name => 'Haml' , :suffixs => ['haml'] },
35
+ { :name => 'Haskell' , :suffixs => ['hs'] },
36
+ { :name => 'HTML' , :suffixs => ['html'] },
37
+ { :name => 'Java' , :suffixs => ['java'] },
38
+ { :name => 'JavaScript' , :suffixs => ['js'] },
39
+ { :name => 'JSON' , :suffixs => ['json'] },
40
+ { :name => 'Lua' , :suffixs => ['lua'] },
41
+ { :name => 'Makefile' , :suffixs => ['mk'] , :filenames => ['Makefile', 'makefile'] },
42
+ { :name => 'Markdown' , :suffixs => ['md', 'markdown'] },
43
+ { :name => 'M4' , :suffixs => ['m4'] },
44
+ { :name => 'Objective-C' , :suffixs => ['m', 'mm'] },
45
+ { :name => 'PEM' , :suffixs => ['pem'] },
46
+ { :name => 'Perl' , :suffixs => ['pl', 'PL', 'pm', 't'] },
47
+ { :name => 'POD' , :suffixs => ['pod'] },
48
+ { :name => 'PHP' , :suffixs => ['php'] },
49
+ { :name => 'Python' , :suffixs => ['py'] },
50
+ { :name => 'Rackup' , :suffixs => ['ru'] },
51
+ { :name => 'Rakefile' , :suffixs => ['rake'] , :filenames => ['Rakefile'] },
52
+ { :name => 'RD' , :suffixs => ['rd'] , :filepatterns => [/rd.ja\Z/] },
53
+ { :name => 'RDoc' , :suffixs => ['rdoc'] },
54
+ { :name => 'Ruby' , :suffixs => ['rb'] },
55
+ { :name => 'RubyGems' , :suffixs => ['gemspec'] },
56
+ { :name => 'Scheme' , :suffixs => ['scm'] },
57
+ { :name => 'sed' , :suffixs => ['sed'] },
58
+ { :name => 'Shell' , :suffixs => ['sh'] },
59
+ { :name => 'SVG' , :suffixs => ['svg'] },
60
+ { :name => 'Tcl' , :suffixs => ['tcl'] },
61
+ { :name => 'Text' , :suffixs => ['txt'] },
62
+ { :name => 'XML' , :suffixs => ['xml'] },
63
+ { :name => 'Yaml' , :suffixs => ['yml', 'yaml'] },
64
+ # { :name => '' , :suffixs => [] , :filenames => [] },
65
+ ]
66
+
67
+ UNKNOWN = 'unknown'
68
+ UNKNOWN_LANGUAGE = {:name => UNKNOWN}
69
+
70
+ def initialize(filename)
71
+ suffix = File.extname(filename)
72
+ suffix = suffix[1..-1]
73
+
74
+ filename = File.basename(filename)
75
+
76
+ @lang = LANGUAGES.find {|v|
77
+ is_found = false
78
+
79
+ if v[:suffixs]
80
+ is_found = v[:suffixs].include?(suffix)
81
+ end
82
+
83
+ if !is_found && v[:filenames]
84
+ is_found = v[:filenames].include?(filename)
85
+ end
86
+
87
+ if !is_found && v[:filepatterns]
88
+ v[:filepatterns].each do |pattern|
89
+ if filename.match pattern
90
+ is_found = true
91
+ break
92
+ end
93
+ end
94
+ end
95
+
96
+ is_found
97
+ }
98
+
99
+ @lang ||= UNKNOWN_LANGUAGE
100
+ end
101
+
102
+ def name
103
+ @lang[:name]
104
+ end
105
+
106
+ def unknown?
107
+ name == UNKNOWN
108
+ end
109
+ end
110
+ end
111
+
@@ -89,7 +89,11 @@ module Milkode
89
89
  end
90
90
 
91
91
  def larger_than_oneline(content)
92
- content && content.count($/) > 1
92
+ begin
93
+ content && content.count($/) > 1
94
+ rescue ArgumentError
95
+ true
96
+ end
93
97
  end
94
98
 
95
99
  def normalize_filename(str)
@@ -174,6 +178,11 @@ module Milkode
174
178
  def git_url?(src)
175
179
  (src =~ /^(:?git[:@])|(:?ssh:)/) != nil
176
180
  end
181
+
182
+ # StringIO patch
183
+ def pipe?(io)
184
+ !io.instance_of?(IO) || !File.pipe?(io)
185
+ end
177
186
  end
178
187
  end
179
188
 
@@ -9,9 +9,9 @@ require 'rubygems'
9
9
  require 'groonga'
10
10
  require 'milkode/common/dbdir'
11
11
  require 'fileutils'
12
- require 'milkode/database/package_table.rb'
13
- require 'milkode/database/document_table.rb'
14
- require 'milkode/database/document_record.rb'
12
+ require 'milkode/database/package_table'
13
+ require 'milkode/database/document_table'
14
+ require 'milkode/database/document_record'
15
15
 
16
16
  module Milkode
17
17
  class GroongaDatabase
@@ -91,7 +91,7 @@ EOF
91
91
  true
92
92
  end
93
93
  end
94
-
94
+
95
95
  private
96
96
 
97
97
  def define_schema
@@ -0,0 +1,242 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2012/09/15
7
+
8
+ require 'milkode/database/groonga_database'
9
+ require 'milkode/common/grenfiletest'
10
+ require 'milkode/common/ignore_checker'
11
+ require 'kconv'
12
+
13
+ module Milkode
14
+ class Updater
15
+ attr_reader :result
16
+
17
+ def initialize(grndb, package_name)
18
+ @grndb = grndb
19
+ @package_name = package_name
20
+ @package = @grndb.packages[@package_name]
21
+ @result = Result.new
22
+ @current_ignore = IgnoreChecker.new
23
+ @options = {}
24
+ @out = $stdout
25
+ end
26
+
27
+ def exec
28
+ # git pull
29
+ if @options[:update_with_git_pull]
30
+ Dir.chdir(@package.directory) { system("git pull") }
31
+ end
32
+
33
+ # cleanup
34
+ unless @options[:no_clean]
35
+ @grndb.documents.cleanup_package_name(@package_name)
36
+ end
37
+
38
+ # update
39
+ update_dir(@package.directory)
40
+
41
+ # 更新時刻の更新
42
+ @grndb.packages.touch(@package_name, :updatetime)
43
+ end
44
+
45
+ def set_package_ignore(ignore_setting)
46
+ @current_ignore.add ignore_setting
47
+ end
48
+
49
+ def enable_no_auto_ignore
50
+ @options[:no_auto_ignore] = true
51
+ end
52
+
53
+ def enable_silent_mode
54
+ @options[:silent_mode] = true
55
+ end
56
+
57
+ def enable_display_info
58
+ @options[:display_info] = true
59
+ end
60
+
61
+ def enable_update_with_git_pull
62
+ @options[:update_with_git_pull] = true
63
+ end
64
+
65
+ def enable_no_clean
66
+ @options[:no_clean] = true
67
+ end
68
+
69
+ class Result
70
+ attr_reader :file_count
71
+ attr_reader :add_count
72
+ attr_reader :update_count
73
+
74
+ def initialize
75
+ @file_count = 0
76
+ @add_count = 0
77
+ @update_count = 0
78
+ end
79
+
80
+ def inc_file_count
81
+ @file_count += 1
82
+ end
83
+
84
+ def inc_add_count
85
+ @add_count += 1
86
+ end
87
+
88
+ def inc_update_count
89
+ @update_count += 1
90
+ end
91
+ end
92
+
93
+ class ResultAccumulator
94
+ attr_reader :package_count
95
+ attr_reader :file_count
96
+ attr_reader :add_count
97
+ attr_reader :update_count
98
+
99
+ def initialize
100
+ @package_count = 0
101
+ @file_count = 0
102
+ @add_count = 0
103
+ @update_count = 0
104
+ end
105
+
106
+ def <<(result)
107
+ @package_count += 1
108
+ @file_count += result.file_count
109
+ @add_count += result.add_count
110
+ @update_count += result.update_count
111
+ end
112
+ end
113
+
114
+ # ---------------------------------------------------------
115
+ private
116
+
117
+ def update_dir(dir)
118
+ if (!FileTest.exist?(dir))
119
+ warning_alert("#{dir} (Not found, skip)")
120
+ elsif (FileTest.directory? dir)
121
+ db_add_dir(dir)
122
+ else
123
+ db_add_file(File.dirname(dir), File.basename(dir), File.basename(dir)) # .bashrc/.bashrc のようになる
124
+ end
125
+ end
126
+
127
+ def db_add_dir(dir)
128
+ searchDirectory(dir, @package_name, "/", 0)
129
+ end
130
+
131
+ def db_add_file(package_dir, restpath, package_name = nil)
132
+ # サイレントモード
133
+ return if @options[:silent_mode]
134
+
135
+ # データベースには先頭の'/'を抜いて登録する
136
+ # 最初から'/'を抜いておけば高速化の余地あり?
137
+ # ignore設定との互換性保持が必要
138
+ restpath = restpath.sub(/^\//, "")
139
+
140
+ # パッケージ名を設定
141
+ package_name = package_name || File.basename(package_dir)
142
+
143
+ # レコードの追加
144
+ result = @grndb.documents.add(package_dir, restpath, package_name)
145
+
146
+ # メッセージの表示
147
+ case result
148
+ when :newfile
149
+ @result.inc_add_count
150
+ alert_info("add_record", File.join(package_dir, restpath))
151
+ when :update
152
+ # @grndb.packages.touch(package_name, :updatetime)
153
+ @result.inc_update_count
154
+ alert_info("update", File.join(package_dir, restpath))
155
+ end
156
+ end
157
+
158
+ def searchDirectory(dirname, packname, path, depth)
159
+ # 現在位置に.gitignoreがあれば無視設定に加える
160
+ add_current_gitignore(dirname, path) unless @options[:no_auto_ignore]
161
+
162
+ # 子の要素を追加
163
+ Dir.foreach(File.join(dirname, path)) do |name|
164
+ next if (name == '.' || name == '..')
165
+
166
+ next_path = File.join(path, name)
167
+ fpath = File.join(dirname, next_path)
168
+ shortpath = File.join(packname, next_path)
169
+
170
+ # 除外ディレクトリならばパス
171
+ next if ignoreDir?(fpath, next_path)
172
+
173
+ # 読み込み不可ならばパス
174
+ next unless FileTest.readable?(fpath)
175
+
176
+ # ファイルならば中身を探索、ディレクトリならば再帰
177
+ case File.ftype(fpath)
178
+ when "directory"
179
+ searchDirectory(dirname, packname, next_path, depth + 1)
180
+ when "file"
181
+ unless ignoreFile?(fpath, next_path)
182
+ db_add_file(dirname, next_path) # shortpathの先頭に'/'が付いているのが気になる
183
+ @result.inc_file_count
184
+ # @out.puts "file_count : #{@file_count}" if (@file_count % 100 == 0)
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ def ignoreDir?(fpath, mini_path)
191
+ FileTest.directory?(fpath) &&
192
+ (GrenFileTest::ignoreDir?(fpath) ||
193
+ package_ignore?(fpath, mini_path))
194
+ end
195
+
196
+ def ignoreFile?(fpath, mini_path)
197
+ GrenFileTest::ignoreFile?(fpath) ||
198
+ GrenFileTest::binary?(fpath) ||
199
+ package_ignore?(fpath, mini_path)
200
+ end
201
+
202
+ def package_ignore?(fpath, mini_path)
203
+ if @current_ignore.ignore?(mini_path)
204
+ alert_info("ignore", fpath)
205
+ true
206
+ else
207
+ false
208
+ end
209
+ end
210
+
211
+ def add_current_gitignore(dirname, path)
212
+ git_ignore = File.join(dirname, path, ".gitignore")
213
+
214
+ if File.exist? git_ignore
215
+ alert_info("add_ignore", git_ignore)
216
+
217
+ open(git_ignore) do |f|
218
+ @current_ignore.add IgnoreSetting.create_from_gitignore(path, f.read)
219
+ end
220
+ end
221
+ end
222
+
223
+ def alert_info(title, msg)
224
+ alert(title, msg) if @options[:display_info]
225
+ end
226
+
227
+ def alert(title, msg)
228
+ if (Util::platform_win?)
229
+ @out.puts "#{title.ljust(10)} : #{Kconv.kconv(msg, Kconv::SJIS)}"
230
+ else
231
+ @out.puts "#{title.ljust(10)} : #{msg}"
232
+ end
233
+ end
234
+
235
+ def warning_alert(msg)
236
+ @out.puts "[warning] #{msg}"
237
+ end
238
+
239
+ end
240
+ end
241
+
242
+