squared 0.4.19 → 0.5.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.
@@ -63,7 +63,6 @@ module Squared
63
63
  hash: %i[green black!],
64
64
  array: %i[blue black!],
65
65
  number: [:magenta],
66
- boolean: [:magenta],
67
66
  undefined: %i[red italic]
68
67
  },
69
68
  logger: {
@@ -94,28 +93,28 @@ module Squared
94
93
  PATH.freeze
95
94
  ARG.freeze
96
95
  VAR.each_value(&:freeze)
97
- VAR[:theme].each_value { |val| val.freeze.each_value(&:freeze) }
96
+ VAR[:theme].each_value(&:freeze)
98
97
  VAR.freeze
99
98
  end
100
99
 
101
100
  module_function
102
101
 
103
- def as_a(obj, meth = nil, flat: nil, compact: false, &blk)
102
+ def as_a(obj, *meth, flat: nil, compact: false, &blk)
104
103
  return [] if obj.nil?
105
104
 
106
105
  unless obj.is_a?(::Array)
107
- obj = if obj.respond_to?(:to_ary)
108
- obj.to_ary
109
- elsif obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
106
+ obj = if obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
110
107
  val
111
108
  else
112
109
  [obj]
113
110
  end
114
111
  end
115
- obj = flat.is_a?(::Numeric) ? obj.flatten(flat) : obj.flatten if flat
112
+ obj = obj.flatten(flat.is_a?(::Numeric) ? flat : nil) if flat
116
113
  obj = obj.compact if compact
117
- obj = obj.map(&meth) if meth
118
- block_given? ? obj.select(&blk) : obj
114
+ obj = obj.map(&meth.shift) until meth.empty?
115
+ return obj unless block_given?
116
+
117
+ obj.select(&blk)
119
118
  end
120
119
  end
121
120
  end
@@ -29,19 +29,13 @@ module Squared
29
29
  bright_white!: '107'
30
30
  }.freeze
31
31
  BOX_GRAPH = ['│', '─', '├', '└', '┬'].freeze
32
- BOX_BORDER = ['│', '─', '', '', '', '', '├', '┤', '┬', '┴'].tap do |val|
33
- if ENV['TERM']&.end_with?('256color')
34
- val.slice!(2, 4)
35
- val.insert(2, '╭', '╮', '╯', '╰')
36
- end
37
- val.freeze
38
- end
32
+ BOX_BORDER = ['│', '─', '', '', '', '', '├', '┤', '┬', '┴'].freeze
39
33
  TEXT_STYLE = [:bold, :dim, :italic, :underline, :blinking, nil, :inverse, :hidden, :strikethrough].freeze
40
34
  private_constant :AIX_TERM, :BOX_GRAPH, :BOX_BORDER, :TEXT_STYLE
41
35
 
42
36
  def enable_aixterm
43
37
  unless (colors = __get__(:colors)).frozen?
44
- colors.merge!(AIX_TERM)
38
+ colors.update(AIX_TERM)
45
39
  end
46
40
  self
47
41
  end
@@ -67,7 +61,7 @@ module Squared
67
61
  end
68
62
  wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
69
63
  code = []
70
- args.concat(Array(styles)).flatten.each_with_index do |type, i|
64
+ args.concat(as_a(styles)).flatten.each_with_index do |type, i|
71
65
  next unless type
72
66
 
73
67
  if index == -1
@@ -141,11 +135,11 @@ module Squared
141
135
  def apply_style(data, key, args, empty: true)
142
136
  return if data.is_a?(::Symbol) && (data = __get__(:theme)[data]).nil?
143
137
 
144
- set = ->(k, v) { data[k.to_sym] = check_style(v, empty: empty) }
138
+ set = ->(k, v) { data[k] = check_style(v, empty: empty) }
145
139
  if key.is_a?(::Hash)
146
140
  key.each { |k, v| set.call(k, v || args) }
147
141
  else
148
- set.call(key, args)
142
+ set.call(key.to_sym, args)
149
143
  end
150
144
  end
151
145
 
@@ -157,8 +151,7 @@ module Squared
157
151
  when Logger::WARN then :warn
158
152
  when Logger::ERROR then :error
159
153
  when Logger::FATAL then :fatal
160
- else :unknown
161
- end
154
+ else :unknown end
162
155
  else
163
156
  level.to_s.downcase.to_sym
164
157
  end
@@ -195,7 +188,7 @@ module Squared
195
188
  end
196
189
  end
197
190
 
198
- def log_console(*args, pipe: 1)
191
+ def puts_oe(*args, pipe: 1)
199
192
  return if args.first == false && args.size == 1
200
193
 
201
194
  if pipe.is_a?(Pathname)
@@ -212,8 +205,6 @@ module Squared
212
205
  (pipe == 2 ? $stderr : $stdout).puts(*args)
213
206
  end
214
207
 
215
- alias puts_oe log_console
216
-
217
208
  module_function
218
209
 
219
210
  def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
@@ -11,24 +11,22 @@ module Squared
11
11
  agree = /^#{Regexp.escape(agree)}$/i if agree.is_a?(::String)
12
12
  cancel = /^#{Regexp.escape(cancel)}$/i if cancel.is_a?(::String)
13
13
  Timeout.timeout(timeout) do
14
- begin
15
- while (ch = Readline.readline(msg))
16
- ch = ch.chomp
17
- case (ch.empty? ? default : ch)
18
- when agree
19
- return true
20
- when cancel
21
- return false
22
- end
23
- attempts -= 1
24
- exit 1 unless attempts > 0
14
+ while (ch = Readline.readline(msg))
15
+ ch = ch.chomp
16
+ case (ch.empty? ? default : ch)
17
+ when agree
18
+ return true
19
+ when cancel
20
+ return false
25
21
  end
26
- rescue Interrupt
27
- puts
28
- exit 0
29
- else
30
- false
22
+ attempts -= 1
23
+ exit 1 unless attempts > 0
31
24
  end
25
+ rescue Interrupt
26
+ puts
27
+ exit 0
28
+ else
29
+ false
32
30
  end
33
31
  end
34
32
 
@@ -37,12 +35,12 @@ module Squared
37
35
  require 'readline'
38
36
  require 'timeout'
39
37
  if list
40
- grep &&= Array(grep).map { |val| Regexp.new(val) }
38
+ grep &&= (grep.is_a?(::Enumerable) ? grep : [grep]).map { |val| Regexp.new(val) }
41
39
  items = []
42
40
  list.each do |val|
43
41
  next if grep&.none? { |pat| pat.match?(line) }
44
42
 
45
- items << val.to_s.chomp
43
+ items << val.chomp
46
44
  puts "#{items.size.to_s.rjust(2)}. #{val}"
47
45
  end
48
46
  max = items.size
@@ -56,33 +54,31 @@ module Squared
56
54
  end
57
55
  valid = ->(s) { s.match?(/^-?\d+$/) && s.to_i.between?(min, max) }
58
56
  Timeout.timeout(timeout) do
59
- begin
60
- while (ch = Readline.readline(msg))
61
- unless (ch = ch.strip).empty?
62
- if multiple
63
- a = ch.split(/\s*,\s*/)
64
- b = a.select { |s| valid.call(s) }.map!(&:to_i).sort
65
- next unless a.size == b.size
66
- return b unless items
67
- next if multiple.is_a?(::Numeric) && multiple != b.size
57
+ while (ch = Readline.readline(msg))
58
+ unless (ch = ch.strip).empty?
59
+ if multiple
60
+ a = ch.split(/\s*,\s*/)
61
+ b = a.select { |s| valid.call(s) }.map!(&:to_i).sort
62
+ next unless a.size == b.size
63
+ return b unless items
64
+ next if multiple.is_a?(::Numeric) && multiple != b.size
68
65
 
69
- return b.map! { |i| items[i - 1] }
70
- elsif valid.call(ch)
71
- return items ? items[ch.to_i - 1] : ch.to_i
72
- end
66
+ return b.map! { |i| items[i - 1] }
67
+ elsif valid.call(ch)
68
+ return items ? items[ch.to_i - 1] : ch.to_i
73
69
  end
74
- attempts -= 1
75
- next if attempts > 0
76
-
77
- exit 1 if force
78
- break
79
70
  end
80
- rescue Interrupt
81
- puts
82
- exit 0
83
- else
84
- multiple ? [] : nil
71
+ attempts -= 1
72
+ next if attempts > 0
73
+ break unless force
74
+
75
+ exit 1
85
76
  end
77
+ rescue Interrupt
78
+ puts
79
+ exit 0
80
+ else
81
+ multiple ? [] : nil
86
82
  end
87
83
  end
88
84
 
@@ -109,7 +105,7 @@ module Squared
109
105
  end
110
106
  ret = (prompt.call || '').strip
111
107
  multiline.each { |val| break if ret.delete_suffix!(val) } if multiline.is_a?(::Enumerable)
112
- exit 1 if force && ret.empty?
108
+ raise_error 'user cancelled' if force && ret.empty?
113
109
  ret
114
110
  else
115
111
  prompt.call
@@ -85,17 +85,17 @@ module Squared
85
85
  end}"
86
86
  end
87
87
 
88
- def shell_split(val, quote: false, force: false, join: nil)
89
- ret = val.shellsplit.map! { |opt| shell_escape(opt, quote: quote, force: force, double: true, option: true) }
88
+ def shell_split(val, join: nil, **kwargs)
89
+ ret = val.shellsplit
90
+ ret.map! { |opt| shell_escape(opt, double: true, option: true, **kwargs) }
90
91
  return ret unless join
91
92
 
92
93
  ret.join(join.is_a?(::String) ? join : ' ')
93
94
  end
94
95
 
95
- def shell_bin(name, env: true)
96
- key = name.upcase
97
- shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
98
- option: false, force: false)
96
+ def line_width(lines)
97
+ ret = [lines.max_by(&:size).size, 80].max
98
+ [ret, Rake.application.terminal_width].min
99
99
  end
100
100
 
101
101
  def fill_option(val, **kwargs)
@@ -104,12 +104,12 @@ module Squared
104
104
  shell_escape(val.start_with?('-') ? val : "--#{val}", **kwargs)
105
105
  end
106
106
 
107
- def quote_option(flag, val, option: true, double: false, merge: false)
108
- shell_option(flag, val, escape: false, option: option, double: double, merge: merge)
107
+ def quote_option(flag, val, **kwargs)
108
+ shell_option(flag, val, escape: false, **kwargs)
109
109
  end
110
110
 
111
- def basic_option(flag, val, merge: false)
112
- shell_option(flag, val, escape: false, force: false, merge: merge)
111
+ def basic_option(flag, val, **kwargs)
112
+ shell_option(flag, val, escape: false, force: false, **kwargs)
113
113
  end
114
114
  end
115
115
  end
@@ -1,55 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'pathname'
4
- require 'rake'
4
+ require 'fileutils'
5
5
 
6
6
  module Squared
7
7
  module Common
8
8
  module System
9
9
  module_function
10
10
 
11
- def shell(*args, name: :system, **kwargs)
12
- if RUBY_ENGINE == 'jruby' && Rake::Win32.windows?
13
- e = kwargs[:exception]
14
- if (dir = kwargs[:chdir]) && ((pwd = Dir.pwd) != dir)
15
- Dir.chdir dir
16
- ret = Kernel.send(name, *args)
17
- Dir.chdir pwd
18
- else
19
- ret = Kernel.send(name, *args)
20
- end
21
- elsif RUBY_VERSION < '2.6'
22
- e = kwargs.delete(:exception)
23
- ret = Kernel.send(name, *args, **kwargs)
11
+ def shell(*args, **kwargs)
12
+ if RUBY_VERSION < '2.6'
13
+ exception = kwargs.delete(:exception)
14
+ ret = Kernel.system(*args, **kwargs)
15
+ return ret if ret || !exception
16
+
17
+ raise $?.to_s
24
18
  else
25
- return Kernel.send(name, *args, **kwargs)
19
+ Kernel.system(*args, **kwargs)
26
20
  end
27
- return ret unless e && !ret && name == :system
28
-
29
- raise $?.to_s
30
21
  end
31
22
 
32
- def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, verbose: true)
33
- src = Pathname.new(src)
34
- dest = Pathname.new(dest)
35
- raise "#{dest.cleanpath} (not found)" if !create && !dest.parent.exist?
23
+ def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, hidden: false,
24
+ verbose: true)
25
+ base = Pathname.new(src)
26
+ target = Pathname.new(dest)
27
+ raise "#{target.cleanpath} (not found)" if !create && !target.parent.exist?
36
28
 
37
29
  subdir = {}
38
- dest.mkpath if create
30
+ target.mkpath if create
31
+ flags = hidden ? [File::FNM_DOTMATCH] : []
39
32
  if pass
40
33
  exclude = []
41
- Array(pass).each { |val| exclude.concat(Dir.glob(src + val)) }
34
+ pass = [pass] unless pass.is_a?(::Array)
35
+ pass.each { |val| exclude.concat(Dir.glob(val, *flags, base: base)) }
42
36
  end
43
- Array(glob).each do |val|
44
- Dir.glob(src + val) do |path|
45
- next if exclude&.include?(path) || (path = Pathname.new(path)).directory?
37
+ (glob.is_a?(::Enumerable) ? glob : [glob]).each do |val|
38
+ Dir.glob(val, *flags, base: base) do |file|
39
+ next if exclude&.include?(file) || (entry = base + file).directory?
46
40
 
47
- dir = dest.join(path.relative_path_from(src)).dirname
41
+ dir = target.join(file).dirname
48
42
  if (data = subdir[dir.to_s])
49
- data << path
43
+ data << entry
50
44
  else
51
45
  dir.mkpath
52
- subdir[dir.to_s] = [path]
46
+ subdir[dir.to_s] = [entry]
53
47
  end
54
48
  end
55
49
  end
@@ -57,7 +51,7 @@ module Squared
57
51
  soft = 0
58
52
  subdir.each do |dir, files|
59
53
  if link
60
- files.dup.tap do |items|
54
+ files.dup.yield_self do |items|
61
55
  files.clear
62
56
  items.each do |file|
63
57
  if file.exist?
@@ -82,15 +76,17 @@ module Squared
82
76
  out = FileUtils.cp(files, dir, verbose: false)
83
77
  count += out.size
84
78
  end
85
- puts [dest.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
79
+ puts [target.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
86
80
  end
87
81
 
88
82
  def copy_guard(src, dest, link: nil, force: false, verbose: true)
89
83
  unless force
90
- if (path = Pathname.new(dest)).directory?
91
- src = Array(src).reject { |val| path.join(File.basename(val)).exist? }
84
+ target = Pathname.new(dest)
85
+ if target.directory?
86
+ src = [src] unless src.is_a?(::Enumerable)
87
+ src = src.reject { |val| target.join(File.basename(val)).exist? }
92
88
  return if src.empty?
93
- elsif path.exist?
89
+ elsif target.exist?
94
90
  return
95
91
  end
96
92
  end
@@ -17,13 +17,13 @@ module Squared
17
17
  val = val.strip
18
18
  return [val, '', ''] unless (i = val.index('='))
19
19
 
20
- last = val[(i + 1)..-1].strip
20
+ last = val[i + 1..-1].strip
21
21
  quote = ''
22
22
  if last =~ /\A(["'])(.+)\1\z/
23
23
  last = $2
24
24
  quote = $1
25
25
  end
26
- [val[0..(i - 1)], last, quote]
26
+ [val[0..i - 1], last, quote]
27
27
  end
28
28
 
29
29
  def task_invoke(*cmd, args: [], exception: true, warning: true)
@@ -88,41 +88,16 @@ module Squared
88
88
  end
89
89
  end
90
90
 
91
- def time_offset(val = nil)
92
- val = DateTime.parse(val) if val.is_a?(::String)
93
- cur = DateTime.now
94
- ret = 0
95
- if (r = /^([+-])(\d+):(\d+):(\d+)$/.match((val || cur).strftime('%::z')))
96
- ret += (r[1] == '+' ? -1 : 1) * ((r[2].to_i * 60 * 60) + (r[3].to_i * 60) + r[4].to_i) * 1000
97
- end
98
- return ret unless val
99
-
100
- (cur.strftime('%Q').to_i + time_offset) - (val.strftime('%Q').to_i + ret)
101
- end
102
-
103
91
  def time_since(val, ms: true)
104
92
  s = ms ? '%s%L' : '%s'
105
93
  Time.now.utc.strftime(s).to_i - Time.parse(val).utc.strftime(s).to_i
106
94
  end
107
95
 
108
- def rand_s(size)
109
- if RUBY_VERSION >= '3.1'
110
- require 'random/formatter'
111
- Random.new.alphanumeric(size)
112
- else
113
- (0...size).map { rand(97..122).chr }.join
114
- end
115
- end
116
-
117
96
  def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil)
118
97
  ret = env_value(key, suffix: suffix, strict: strict)
119
98
  return ret == equals.to_s unless equals.nil?
120
99
 
121
- ret.empty? || (ignore && Array(ignore).any? { |val| val.to_s == ret }) ? default : ret
122
- end
123
-
124
- def env_key(*val)
125
- val.join('_').gsub(/\W+/, '_').upcase
100
+ ret.empty? || (ignore && as_a(ignore).any? { |val| val.to_s == ret }) ? default : ret
126
101
  end
127
102
 
128
103
  def env_value(key, default = '', suffix: nil, strict: false)
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'set'
4
+
3
5
  require_relative 'common/base'
4
- require_relative 'common/class'
5
6
  require_relative 'common/format'
6
7
  require_relative 'common/prompt'
7
8
  require_relative 'common/shell'
@@ -15,7 +15,8 @@ module Squared
15
15
  def parse(gem, namespace, ext = [pkg])
16
16
  require gem
17
17
  obj = eval namespace
18
- Array(ext).each { |val| @@mime_obj[val] = [obj, ext] }
18
+ ext = [ext] unless ext.is_a?(Array)
19
+ ext.each { |val| @@mime_obj[val] = [obj, ext] }
19
20
  rescue LoadError, NameError => e
20
21
  warn e
21
22
  nil
@@ -26,7 +27,7 @@ module Squared
26
27
  def link(project, main = project.dependfile.basename, name = nil, **kwargs, &blk)
27
28
  return unless project.enabled?
28
29
 
29
- ret = Viewer.new(main, name, project: project, **kwargs)
30
+ ret = new(main, name, project: project, **kwargs)
30
31
  ret.instance_eval(&blk) if block_given?
31
32
  ret
32
33
  end
@@ -88,16 +89,16 @@ module Squared
88
89
  @required = true
89
90
  project ? [project, 'not found'] : ['name', 'missing']
90
91
  end
91
- warn log_message(Logger::WARN, msg, subject: self.class, hint: hint)
92
+ warn log_message(Logger::WARN, msg, subject: self.class, hint: hint, pass: true)
92
93
  end
93
94
 
94
95
  def build
95
96
  return unless enabled?
96
97
 
97
- namespace task_name(name) do |ns|
98
+ namespace(ns = task_name(name)) do
98
99
  @mime.each do |type, items|
99
100
  items.each do |command, file, opts|
100
- next if Rake::Task.task_defined?("#{ns.scope.path}:#{command}:#{type}")
101
+ next if Rake::Task.task_defined?("#{ns}:#{command}:#{type}")
101
102
 
102
103
  namespace command do
103
104
  unless (data = @@mime_obj[type])
@@ -128,7 +129,7 @@ module Squared
128
129
  require(gem || type)
129
130
  obj = eval namespace
130
131
  else
131
- Array(ext).each do |val|
132
+ as_a(ext).each do |val|
132
133
  next unless (data = @@mime_obj[val])
133
134
 
134
135
  obj = data.first
@@ -136,7 +137,7 @@ module Squared
136
137
  end
137
138
  end
138
139
  if obj
139
- ext << type if (ext = Array(ext)).empty?
140
+ ext << type if (ext = as_a(ext)).empty?
140
141
  if !file && target?
141
142
  ext.each do |val|
142
143
  next unless (out = basepath("#{main}.#{val}")).exist?
@@ -169,7 +170,7 @@ module Squared
169
170
  end
170
171
 
171
172
  def style(name, *args)
172
- apply_style(theme, name, args)
173
+ apply_style theme, name, args
173
174
  self
174
175
  end
175
176
 
@@ -196,7 +197,7 @@ module Squared
196
197
  private
197
198
 
198
199
  def puts(*args)
199
- log_console(*args, pipe: pipe)
200
+ puts_oe(*args, pipe: pipe)
200
201
  end
201
202
 
202
203
  def log
@@ -212,7 +213,7 @@ module Squared
212
213
  file = nil
213
214
  ext[0] = mime
214
215
  elsif file
215
- keys.unshift(file)
216
+ keys.prepend(file)
216
217
  alt = basepath("#{main}.{#{ext.join(',')}}")
217
218
  file = Dir[alt].first
218
219
  else
@@ -242,15 +243,14 @@ module Squared
242
243
  [
243
244
  { pat: /\A((?:[^:]|(?<! ):(?! ))+)\z/, styles: theme[:banner] },
244
245
  { pat: /\A(.*?)(<[^>]+>)(.+)\z/m, styles: theme[:undefined], index: 2 },
245
- { pat: /\A(.+)( : (?!undefined).+)\z/m, styles: theme[:key] },
246
- { pat: /\A(.+ : )(-?[\d.]+)(\s*)\z/m, styles: theme[:number],
246
+ { pat: /\A((?~ : ))( : (?!undefined).+)\z/m, styles: theme[:key] },
247
+ { pat: /\A((?~: ): )(-?[\d.]+)(\s*)\z/m, styles: theme[:number],
247
248
  index: 2 },
248
- { pat: /\A(.+ : ")(.+)("\s*)\z/m, styles: theme[:string], index: 2 },
249
- { pat: /\A(.+ : \{)(.+)(\}\s*)\z/m, styles: theme[:hash], index: 2 },
250
- { pat: /\A(.+ : \[)(.+)(\]\s*)\z/m, styles: theme[:array], index: 2 },
251
- { pat: /\A(.+ : )(true|false)(\s*)\z/m, styles: theme[:boolean],
249
+ { pat: /\A((?~: ): ")(.+)("\s*)\z/m, styles: theme[:string], index: 2 },
250
+ { pat: /\A((?~: ): \{)(.+)(\}\s*)\z/m, styles: theme[:hash], index: 2 },
251
+ { pat: /\A((?~: ): \[)(.+)(\]\s*)\z/m, styles: theme[:array],
252
252
  index: 2 },
253
- { pat: /\A(.+ : (?!undefined))([^"\[{].*)\z/m, styles: theme[:value],
253
+ { pat: /\A((?~: ): (?!undefined))([^"\[{].*)\z/m, styles: theme[:value],
254
254
  index: 2 }
255
255
  ]
256
256
  end, border: theme[:border])
@@ -309,7 +309,7 @@ module Squared
309
309
  return unless Rake::TaskManager.record_task_metadata
310
310
 
311
311
  val = "#{ext.first}[#{target ? '' : "file?=#{File.basename(main)}.#{ext.last},"}keys+]"
312
- args = *name.split(':').push(command, val)
312
+ args = *name.split(':').append(command, val)
313
313
  if project
314
314
  project.workspace.task_desc(*args)
315
315
  else
@@ -347,7 +347,7 @@ module Squared
347
347
  end
348
348
 
349
349
  def basepath(file)
350
- project ? project.basepath(file) : Pathname.new(file).realdirpath
350
+ project ? project.basepath(file) : Pathname.pwd + file
351
351
  end
352
352
  end
353
353
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.4.19'
4
+ VERSION = '0.5.0'
5
5
  end