Skip to content

Commit dfed51f

Browse files
committed
General improvements.
1 parent 231b94b commit dfed51f

File tree

4 files changed

+133
-121
lines changed

4 files changed

+133
-121
lines changed

lib/executable/core_ext.rb

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1 @@
1-
class UnboundMethod
2-
if !method_defined?(:source_location)
3-
if Proc.method_defined? :__file__ # /ree/
4-
def source_location
5-
[__file__, __line__] rescue nil
6-
end
7-
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
8-
require 'java'
9-
def source_location
10-
to_java.source_location(Thread.current.to_java.getContext())
11-
end
12-
end
13-
end
14-
15-
#
16-
def comment
17-
Source.get_above_comment(*source_location)
18-
end
19-
20-
# Source lookup.
21-
#
22-
module Source
23-
extend self
24-
25-
# Read and cache file.
26-
#
27-
# @param file [String] filename, should be full path
28-
#
29-
# @return [Array] file content in array of lines
30-
def read(file)
31-
@read ||= {}
32-
@read[file] ||= File.readlines(file)
33-
end
34-
35-
# Get comment from file searching up from given line number.
36-
#
37-
# @param file [String] filename, should be full path
38-
# @param line [Integer] line number in file
39-
#
40-
def get_above_comment(file, line)
41-
get_above_comment_lines(file, line).join("\n").strip
42-
end
43-
44-
# Get comment from file searching up from given line number.
45-
#
46-
# @param file [String] filename, should be full path
47-
# @param line [Integer] line number in file
48-
#
49-
def get_above_comment_lines(file, line)
50-
text = read(file)
51-
index = line - 1
52-
while index >= 0 && text[index] !~ /^\s*\#/
53-
return [] if text[index] =~ /^\s*end/
54-
index -= 1
55-
end
56-
rindex = index
57-
while text[index] =~ /^\s*\#/
58-
index -= 1
59-
end
60-
result = text[index..rindex]
61-
result = result.map{ |s| s.strip }
62-
result = result.reject{ |s| s[0,1] != '#' }
63-
result = result.map{ |s| s.sub(/^#/,'').strip }
64-
#result = result.reject{ |s| s == "" }
65-
result
66-
end
67-
68-
# Get comment from file searching down from given line number.
69-
#
70-
# @param file [String] filename, should be full path
71-
# @param line [Integer] line number in file
72-
#
73-
def get_following_comment(file, line)
74-
get_following_comment_lines(file, line).join("\n").strip
75-
end
76-
77-
# Get comment from file searching down from given line number.
78-
#
79-
# @param file [String] filename, should be full path
80-
# @param line [Integer] line number in file
81-
#
82-
def get_following_comment_lines(file, line)
83-
text = read(file)
84-
index = line || 0
85-
while text[index] !~ /^\s*\#/
86-
return nil if text[index] =~ /^\s*(class|module)/
87-
index += 1
88-
end
89-
rindex = index
90-
while text[rindex] =~ /^\s*\#/
91-
rindex += 1
92-
end
93-
result = text[index..(rindex-2)]
94-
result = result.map{ |s| s.strip }
95-
result = result.reject{ |s| s[0,1] != '#' }
96-
result = result.map{ |s| s.sub(/^#/,'').strip }
97-
result.join("\n").strip
98-
end
99-
100-
end
101-
102-
end
1+
require 'executable/core_ext/unbound_method'
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
class UnboundMethod
2+
if !method_defined?(:source_location)
3+
if Proc.method_defined? :__file__ # /ree/
4+
def source_location
5+
[__file__, __line__] rescue nil
6+
end
7+
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
8+
require 'java'
9+
def source_location
10+
to_java.source_location(Thread.current.to_java.getContext())
11+
end
12+
end
13+
end
14+
15+
#
16+
def comment
17+
Source.get_above_comment(*source_location)
18+
end
19+
20+
# Source lookup.
21+
#
22+
module Source
23+
extend self
24+
25+
# Read and cache file.
26+
#
27+
# @param file [String] filename, should be full path
28+
#
29+
# @return [Array] file content in array of lines
30+
def read(file)
31+
@read ||= {}
32+
@read[file] ||= File.readlines(file)
33+
end
34+
35+
# Get comment from file searching up from given line number.
36+
#
37+
# @param file [String] filename, should be full path
38+
# @param line [Integer] line number in file
39+
#
40+
def get_above_comment(file, line)
41+
get_above_comment_lines(file, line).join("\n").strip
42+
end
43+
44+
# Get comment from file searching up from given line number.
45+
#
46+
# @param file [String] filename, should be full path
47+
# @param line [Integer] line number in file
48+
#
49+
def get_above_comment_lines(file, line)
50+
text = read(file)
51+
index = line - 1
52+
while index >= 0 && text[index] !~ /^\s*\#/
53+
return [] if text[index] =~ /^\s*end/
54+
index -= 1
55+
end
56+
rindex = index
57+
while text[index] =~ /^\s*\#/
58+
index -= 1
59+
end
60+
result = text[index..rindex]
61+
result = result.map{ |s| s.strip }
62+
result = result.reject{ |s| s[0,1] != '#' }
63+
result = result.map{ |s| s.sub(/^#/,'').strip }
64+
#result = result.reject{ |s| s == "" }
65+
result
66+
end
67+
68+
# Get comment from file searching down from given line number.
69+
#
70+
# @param file [String] filename, should be full path
71+
# @param line [Integer] line number in file
72+
#
73+
def get_following_comment(file, line)
74+
get_following_comment_lines(file, line).join("\n").strip
75+
end
76+
77+
# Get comment from file searching down from given line number.
78+
#
79+
# @param file [String] filename, should be full path
80+
# @param line [Integer] line number in file
81+
#
82+
def get_following_comment_lines(file, line)
83+
text = read(file)
84+
index = line || 0
85+
while text[index] !~ /^\s*\#/
86+
return nil if text[index] =~ /^\s*(class|module)/
87+
index += 1
88+
end
89+
rindex = index
90+
while text[rindex] =~ /^\s*\#/
91+
rindex += 1
92+
end
93+
result = text[index..(rindex-2)]
94+
result = result.map{ |s| s.strip }
95+
result = result.reject{ |s| s[0,1] != '#' }
96+
result = result.map{ |s| s.sub(/^#/,'').strip }
97+
result.join("\n").strip
98+
end
99+
100+
end
101+
102+
end

lib/executable/domain.rb

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module Executable
33
#
44
module Domain
55

6-
#
6+
# TODO: Should this be in Help class?
77
def usage_name
88
list = []
99
ancestors.each do |ancestor|
@@ -38,26 +38,32 @@ def calculate_command_name(ancestor)
3838
# @name
3939
# end
4040
#
41+
# TODO: Currently there is an unfortunate issue with using
42+
# this helper method. If does not correctly record the location
43+
# the method is called, so default help message is wrong.
4144
#
4245
def attr_switch(name)
43-
attr_writer name
44-
module_eval %{
46+
file, line = *caller[0].split(':')[0..1]
47+
module_eval(<<-END, file, line.to_i)
48+
def #{name}=(value)
49+
@#{name}=(value)
50+
end
4551
def #{name}?
4652
@#{name}
4753
end
48-
}
54+
END
4955
end
5056

5157
#
52-
#
58+
# Alias a switch.
5359
#
5460
def alias_switch(name, origin)
5561
alias_method "#{name}=", "#{origin}="
5662
alias_method "#{name}?", "#{origin}?"
5763
end
5864

5965
#
60-
#
66+
# Alias an accessor.
6167
#
6268
def alias_accessor(name, origin)
6369
alias_method "#{name}=", "#{origin}="
@@ -72,7 +78,8 @@ def inspect
7278
end
7379

7480
#
75-
# Returns `help.to_s`.
81+
# Returns `help.to_s`. If you want to provide your own help
82+
# text you can override this method in your command subclass.
7683
#
7784
def to_s
7885
cli.to_s

lib/executable/help.rb

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ module Executable
55
# Encpsulates command help for defining and displaying well formated help
66
# output in plain text, markdown or via manpages if found.
77
#
8-
# TODO: Currently doesn't hande aliases/shortcuts well and simply
9-
# lists them as separate entries.
10-
#
118
# Creating text help in the fly is fine for personal projects, but
129
# for production app, ideally you want to have man pages. You can
1310
# use the #markdown method to generate `.ronn` files and use the
@@ -200,8 +197,8 @@ def text
200197
end
201198

202199
if !options.empty?
203-
s << "OPTIONS\n" + options.map{ |max, opt|
204-
" %2s%-#{max}s %s" % [opt.mark, opt.usage, opt.description]
200+
s << "OPTIONS\n" + options.map{ |max, opts, desc|
201+
" %-#{max}s %s" % [opts.join(' '), desc]
205202
}.join("\n")
206203
end
207204

@@ -242,8 +239,8 @@ def markdown
242239

243240
if !options.empty?
244241
s << "## OPTIONS"
245-
s << options.map{ |max, opt|
246-
" * `#{opt.mark}%s`:\n %s" % [opt.usage, opt.description]
242+
s << options.map{ |max, opts, desc|
243+
" * `%s`:\n %s" % [opts.join(' '), desc]
247244
}.join("\n\n")
248245
end
249246

@@ -303,10 +300,17 @@ def text_options
303300
end
304301
end
305302

306-
max = option_list.map{ |opt| opt.usage.size }.max.to_i + 2
303+
# if two options have the same description, they must aliases
304+
aliased_options = option_list.group_by{ |opt| opt.description }
305+
306+
list = aliased_options.map do |desc, opts|
307+
[opts.map{ |o| "%s%s" % [o.mark, o.usage] }, desc]
308+
end
309+
310+
max = list.map{ |opts, desc| opts.join(' ').size }.max.to_i + 2
307311

308-
option_list.map do |opt|
309-
[max, opt]
312+
list.map do |opts, desc|
313+
[max, opts, desc]
310314
end
311315
end
312316

@@ -352,11 +356,11 @@ def method_list
352356
-1
353357
ancestors = cli_class.ancestors[0...stop_at]
354358
ancestors.reverse_each do |a|
355-
a.instance_methods(false).each do |m|
359+
a.public_instance_methods(false).each do |m|
356360
list << cli_class.instance_method(m)
357361
end
358362
end
359-
list
363+
list #.uniq
360364
end
361365

362366
#

0 commit comments

Comments
 (0)