console_runner 0.1.8 → 0.1.9
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/README.md +63 -69
- data/lib/console_runner.rb +23 -38
- data/lib/console_runner/version.rb +1 -1
- data/lib/file_parser.rb +18 -5
- data/lib/method_parser.rb +10 -2
- data/lib/{cmd_parser.rb → trollop_configurator.rb} +14 -28
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c16db9e220aea79fb56dcfedbefaf35822d5759
|
4
|
+
data.tar.gz: 04a996f93da398cc7b3cf78054d4cbc0410d2572
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b250ca7da42c8f2c2940577d0706a8ebc800af3463aef7f94b75c2a6aa626e809262b2e37b5c12dce3f515855bfe39ef0bd0fcf1a67683b8338f6c51458b9f93
|
7
|
+
data.tar.gz: 9e0c76daa906eb6cb2224caa38d86ad0e9df4adf374c79979a3ed15186625326161f5e7bb596049c3c9fa6d101ee26987befba7298460ee3830c5b7f1bca172a
|
data/README.md
CHANGED
@@ -5,9 +5,47 @@
|
|
5
5
|
[![Code Climate][CC img]][Code Climate]
|
6
6
|
[![Coverage Status][CS img]][Coverage Status]
|
7
7
|
|
8
|
-
This gem provides you an ability to run any Ruby method from command-line
|
8
|
+
This gem provides you an ability to run any Ruby method from command-line. No special code modifications required!.
|
9
|
+
`console_runner` is a smart mix of [YARD](http://yardoc.org/) and [Trollop](http://manageiq.github.io/trollop/) gems.
|
10
|
+
> 1. it parses [YARD](http://yardoc.org/) annotations of classes and methods to 'understand' your code
|
11
|
+
> 2. it generates friendly unix-like help menu for your tool (using [Trollop](http://manageiq.github.io/trollop/) gem)
|
12
|
+
> 3. it parses command-line input and run your Ruby code in a proper way
|
13
|
+
|
14
|
+
Just 4 simple steps to make your code runnable from terminal:
|
15
|
+
1. Just add `@runnable` tag in
|
16
|
+
|
9
17
|
One thing you need to do is to add an [YARD](http://yardoc.org/) tag annotation `@runnable`.
|
10
18
|
|
19
|
+
## Usage
|
20
|
+
`console_runner` extends [YARD](http://yardoc.org/) with a new tag: `@runnable`. You need to set this tag in a Class and Method annotation. After that it will be possible to call this method from command-line.
|
21
|
+
Usage instructions are as simple as one, two, three:
|
22
|
+
1. Add `@runnable` tag
|
23
|
+
2. Now you can run your tool from terminal by `c_run /path/to/class.rb_file` command
|
24
|
+
3. PROFIT! (:
|
25
|
+
|
26
|
+
### Example
|
27
|
+
1. Install `console_runner` gem
|
28
|
+
2. Put some code to `/home/user/project/my_class.rb`
|
29
|
+
```ruby
|
30
|
+
# @runnable
|
31
|
+
class MyClass
|
32
|
+
|
33
|
+
# @runnable
|
34
|
+
def say_hello
|
35
|
+
puts 'Hello!'
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
```
|
40
|
+
3. Run terminal command to run `say_hello` method
|
41
|
+
```bash
|
42
|
+
c_run /home/user/project/my_class.rb say_hello
|
43
|
+
|
44
|
+
-> Hello!
|
45
|
+
```
|
46
|
+
|
47
|
+
Read FAQ for more examples.
|
48
|
+
|
11
49
|
## Installation
|
12
50
|
|
13
51
|
Add this line to your application's Gemfile:
|
@@ -24,84 +62,40 @@ Or install it yourself as:
|
|
24
62
|
|
25
63
|
$ gem install console_runner
|
26
64
|
|
27
|
-
##
|
28
|
-
|
29
|
-
|
30
|
-
|
65
|
+
## FAQ
|
66
|
+
##### **Can I add documentation for my tool and customize help page content?**
|
67
|
+
Yes. Any text placed after `@runnable` tag will be displayed on the help page. You can add any additional information about how to use your tool there.
|
68
|
+
> **Tip**: You can use multi-line text as well
|
69
|
+
|
70
|
+
**Example:**
|
31
71
|
```ruby
|
32
|
-
# This
|
33
|
-
|
34
|
-
# shows that this class can be runnable via bash command line.
|
35
|
-
#
|
36
|
-
# You can mark any method (class method or instance method) with @runnable tag to show you want the method to be executable.
|
37
|
-
# We name class method as *class action* and instance method as *instance action* or just *action*.
|
38
|
-
# Instance action requires #initialize method to be executed first. `console_runner` tool invokes #initialize
|
39
|
-
# method automatically.
|
40
|
-
#
|
41
|
-
# @author Yuri Karpovich
|
42
|
-
#
|
43
|
-
# @runnable This is your "smart" assistant tool.
|
44
|
-
# NOTE: This message will be shown in your tool in --help menu.
|
45
|
-
#
|
46
|
-
# @since 0.1.0
|
47
|
-
class SimpleSiri
|
48
|
-
|
49
|
-
def initialize
|
50
|
-
@name = 'Siri'
|
51
|
-
@age = Random.rand 100
|
52
|
-
end
|
53
|
-
|
54
|
-
# Say something
|
55
|
-
#
|
56
|
-
# @runnable
|
57
|
-
# @return [String]
|
58
|
-
# @param [String] what_to_say ask name or age of Siri
|
59
|
-
def say(what_to_say)
|
60
|
-
case what_to_say.downcase
|
61
|
-
when 'name'
|
62
|
-
puts 'My name is ' + @name
|
63
|
-
when 'age'
|
64
|
-
puts "I'm #{@age} years old"
|
65
|
-
else
|
66
|
-
puts "I don't know".green
|
67
|
-
end
|
68
|
-
end
|
72
|
+
# @runnable This tool can talk to you. Run it when you are lonely.
|
73
|
+
class MyClass
|
69
74
|
|
75
|
+
def initialize
|
76
|
+
@hello_msg = 'Hello!'
|
77
|
+
@bye_msg = 'Good Bye!'
|
78
|
+
end
|
79
|
+
|
80
|
+
# @runnable Say 'Hello' to you.
|
81
|
+
def say_hello
|
82
|
+
puts @hello_msg
|
83
|
+
end
|
84
|
+
|
85
|
+
# @runnable Say 'Good Bye' to you.
|
86
|
+
def say_bye
|
87
|
+
puts @bye_msg
|
88
|
+
end
|
89
|
+
|
70
90
|
end
|
71
91
|
```
|
72
92
|
|
73
|
-
Then you can run the tool in your console:
|
74
|
-
```bash
|
75
|
-
c_run ruby_class.rb say --help
|
76
|
-
|
77
|
-
This is your "smart" assistant tool.
|
78
|
-
NOTE: This message will be shown in your tool in --help menu.
|
79
|
-
-h, --help Show this message
|
80
|
-
-w, --what-to-say=<s> (Ruby class: String) ask name or age of Siri
|
81
|
-
```
|
82
|
-
|
83
93
|
```bash
|
84
|
-
|
85
|
-
|
86
|
-
=======================================================
|
87
|
-
Global options:
|
88
|
-
help = false
|
89
|
-
INIT: initialize
|
90
|
-
INIT options:
|
91
|
-
|
92
|
-
Subcommand: say
|
93
|
-
Subcommand options:
|
94
|
-
what_to_say = age
|
95
|
-
=======================================================
|
96
|
-
Start Time: 2017-04-11 21:39:40 +0300
|
97
|
-
I'm 78 years old
|
98
|
-
Finish Time: 2017-04-11 21:39:40 +0300 (Duration: 0.0 minutes)
|
99
|
-
|
94
|
+
TODO example
|
100
95
|
```
|
101
96
|
|
102
97
|
## ToDo
|
103
98
|
- fix help menu for action: action help text should be displayed, list of available actions should be displayed
|
104
|
-
- write good readme
|
105
99
|
|
106
100
|
## Development
|
107
101
|
|
data/lib/console_runner.rb
CHANGED
@@ -1,77 +1,62 @@
|
|
1
1
|
require 'file_parser'
|
2
|
-
require '
|
2
|
+
require 'trollop_configurator'
|
3
3
|
require 'runner'
|
4
4
|
require 'console_runner/version'
|
5
5
|
|
6
|
-
|
6
|
+
# console_runner logic is here
|
7
7
|
module ConsoleRunner
|
8
8
|
file_from_arg = ARGV.shift
|
9
9
|
raise ConsoleRunnerError, 'Specify file to be executed' unless file_from_arg
|
10
10
|
file_path = File.realpath file_from_arg
|
11
11
|
file_parser = FileParser.new(file_path)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
if runnable_classes.count != 1
|
16
|
-
raise ConsoleRunnerError, "One runnable Class should be specified in file.
|
17
|
-
Runnable class should be marked with @#{FileParser::RUNNABLE_TAG} tag"
|
18
|
-
end
|
19
|
-
|
20
|
-
clazz = runnable_classes.first
|
21
|
-
all_methods = file_parser.list_methods(:all, clazz)
|
22
|
-
runnable_methods = file_parser.list_methods(:runnable, clazz)
|
23
|
-
initialize_method = all_methods.find { |m| m.name == :initialize }
|
24
|
-
run_method = all_methods.find { |m| m.name == :run }
|
25
|
-
|
26
|
-
|
27
|
-
cmd = ARGV[0]
|
28
|
-
action_methods = runnable_methods.select { |m| m.name.to_s == cmd }
|
29
|
-
if action_methods.count > 1
|
12
|
+
cmd = ARGV[0]
|
13
|
+
actions = file_parser.runnable_methods.select { |m| m.name.to_s == cmd }
|
14
|
+
if actions.count > 1
|
30
15
|
raise(
|
31
16
|
ConsoleRunnerError,
|
32
|
-
"Class and Instance methods have the same name (#{cmd}).
|
17
|
+
"Class and Instance methods have the same name (#{cmd}). Actions names should be unique"
|
33
18
|
)
|
34
19
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
raise ConsoleRunnerError, "Cannot run! You haven't specify any method to run." unless
|
39
|
-
|
20
|
+
action = actions.first
|
21
|
+
action ||= file_parser.run_method
|
22
|
+
trol_config = TrollopConfigurator.new(file_parser)
|
23
|
+
raise ConsoleRunnerError, "Cannot run! You haven't specify any method to run." unless action
|
24
|
+
trol_config.parse_method action
|
40
25
|
|
41
26
|
|
42
27
|
puts '======================================================='
|
43
28
|
puts 'Global options:'
|
44
|
-
puts
|
45
|
-
if initialize_method
|
46
|
-
puts "INIT: #{initialize_method.name}"
|
29
|
+
puts trol_config.global_opts.map { |k, v| " #{k} = #{v}" }.join("\n")
|
30
|
+
if file_parser.initialize_method
|
31
|
+
puts "INIT: #{file_parser.initialize_method.name}"
|
47
32
|
puts 'INIT options:'
|
48
|
-
puts
|
33
|
+
puts trol_config.init_method.cmd_opts.map { |k, v| " #{k} = #{v}" }.join("\n")
|
49
34
|
end
|
50
|
-
puts "Subcommand: #{
|
35
|
+
puts "Subcommand: #{action.name}"
|
51
36
|
puts 'Subcommand options:'
|
52
|
-
puts
|
37
|
+
puts trol_config.method.cmd_opts.map { |k, v| " #{k} = #{v}" }.join("\n")
|
53
38
|
puts "Remaining arguments: #{ARGV.inspect}" if ARGV != []
|
54
39
|
puts '======================================================='
|
55
40
|
|
56
41
|
|
57
42
|
Runner.run {
|
58
43
|
require file_path
|
59
|
-
class_full_name = clazz.title
|
44
|
+
class_full_name = file_parser.clazz.title
|
60
45
|
raise ConsoleRunnerError, "#{class_full_name} is not defined" unless Module.const_defined?(class_full_name)
|
61
46
|
klass_obj = Module.const_get(class_full_name)
|
62
|
-
method_type =
|
63
|
-
method_params =
|
47
|
+
method_type = action.scope
|
48
|
+
method_params = trol_config.method.params_array
|
64
49
|
|
65
50
|
case method_type
|
66
51
|
when :class
|
67
|
-
klass_obj.send(
|
52
|
+
klass_obj.send(action.name, *method_params)
|
68
53
|
when :instance
|
69
|
-
init_method =
|
54
|
+
init_method = trol_config.init_method
|
70
55
|
init_params = []
|
71
56
|
init_params = init_method.params_array if init_method
|
72
57
|
# TODO catch errors
|
73
58
|
obj = klass_obj.new(*init_params)
|
74
|
-
obj.send(
|
59
|
+
obj.send(action.name, *method_params)
|
75
60
|
else
|
76
61
|
raise ConsoleRunnerError, "Unknown method type: #{method_type}"
|
77
62
|
end
|
data/lib/file_parser.rb
CHANGED
@@ -5,8 +5,10 @@ require 'console_runner_error'
|
|
5
5
|
class FileParser
|
6
6
|
RUNNABLE_TAG = :runnable
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
attr_reader :clazz,
|
9
|
+
:runnable_methods,
|
10
|
+
:initialize_method,
|
11
|
+
:run_method
|
10
12
|
|
11
13
|
# Parse file with #YARD::CLI::Stats
|
12
14
|
#
|
@@ -15,9 +17,18 @@ class FileParser
|
|
15
17
|
raise ConsoleRunnerError "Cannot find file #{file_path}" unless File.exist?(file_path)
|
16
18
|
code = YARD::CLI::Stats.new
|
17
19
|
code.run(file_path)
|
18
|
-
@all_objects
|
20
|
+
@all_objects = code.all_objects
|
21
|
+
runnable_classes = list_classes(:runnable)
|
22
|
+
raise ConsoleRunnerError, 'At least one runnable Class should be specified in file' if runnable_classes.count != 1
|
23
|
+
@clazz = runnable_classes.first
|
24
|
+
all_methods = list_methods(:all, clazz)
|
25
|
+
@runnable_methods = list_methods(:runnable, clazz)
|
26
|
+
@initialize_method = all_methods.find { |m| m.name == :initialize }
|
27
|
+
@run_method = all_methods.find { |m| m.name == :run }
|
19
28
|
end
|
20
29
|
|
30
|
+
private
|
31
|
+
|
21
32
|
# List of methods
|
22
33
|
# @param [Symbol] scope :all - list all methods, :runnable - list only runnable methods
|
23
34
|
# @param [YARD::CodeObjects::ClassObject, nil] clazz list methods of specified class only
|
@@ -93,9 +104,11 @@ YARD::Tags::Library.define_tag 'Console Tool Description', FileParser::RUNNABLE_
|
|
93
104
|
module YARD
|
94
105
|
module CLI
|
95
106
|
class Stats < Yardoc
|
96
|
-
def print_statistics;
|
107
|
+
def print_statistics;
|
108
|
+
end
|
97
109
|
|
98
|
-
def print_undocumented_objects;
|
110
|
+
def print_undocumented_objects;
|
111
|
+
end
|
99
112
|
end
|
100
113
|
end
|
101
114
|
end
|
data/lib/method_parser.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
class MethodParser
|
3
3
|
attr_reader :method,
|
4
4
|
:name,
|
5
|
-
:param_tags,
|
6
|
-
:option_tags
|
5
|
+
:param_tags, # All method parameters tags
|
6
|
+
:option_tags # Only options tags
|
7
7
|
|
8
8
|
attr_accessor :cmd_opts
|
9
9
|
|
@@ -15,6 +15,14 @@ class MethodParser
|
|
15
15
|
@param_tags = FileParser.select_param_tags @method
|
16
16
|
@option_tags = FileParser.select_option_tags @method
|
17
17
|
@cmd_opts = nil
|
18
|
+
same_params = param_tags_names & option_tags_names
|
19
|
+
if same_params.count > 0
|
20
|
+
raise(
|
21
|
+
ConsoleRunnerError,
|
22
|
+
"You have the same name for @param and @option attribute(s): #{same_params.join(', ')}.
|
23
|
+
Use different names to `console_runner` be able to run #{@name} method."
|
24
|
+
)
|
25
|
+
end
|
18
26
|
end
|
19
27
|
|
20
28
|
# Prepare
|
@@ -2,7 +2,7 @@ require 'trollop'
|
|
2
2
|
require 'method_parser'
|
3
3
|
|
4
4
|
# Parses command line and configure #Trollop
|
5
|
-
class
|
5
|
+
class TrollopConfigurator
|
6
6
|
attr_reader :global_opts, :method, :init_method
|
7
7
|
TYPES_MAPPINGS = {
|
8
8
|
'String' => :string,
|
@@ -16,8 +16,12 @@ class CmdParser
|
|
16
16
|
'Array(Float)' => :floats,
|
17
17
|
'Array(Boolean)' => :booleans
|
18
18
|
}.freeze
|
19
|
-
|
20
|
-
|
19
|
+
|
20
|
+
# Generate tool help menu.
|
21
|
+
# IMPORTANT! Should be executed before ARGV.shift
|
22
|
+
def initialize(file_parser)
|
23
|
+
runnable_methods = file_parser.runnable_methods
|
24
|
+
init_method = file_parser.initialize_method
|
21
25
|
clazz = runnable_methods.first.parent
|
22
26
|
sub_commands = runnable_methods.map { |m| m.name.to_s }
|
23
27
|
@parser = Trollop::Parser.new
|
@@ -26,16 +30,6 @@ class CmdParser
|
|
26
30
|
|
27
31
|
if init_method
|
28
32
|
@init_method = MethodParser.new init_method
|
29
|
-
same_params = @init_method.param_tags_names & @init_method.option_tags_names
|
30
|
-
if same_params.count > 0
|
31
|
-
raise(
|
32
|
-
ConsoleRunnerError,
|
33
|
-
"You have the same name for @param and @option attribute(s): #{same_params.join(', ')}.
|
34
|
-
Use different names to `console_runner` be able to run #{@init_method.name} method."
|
35
|
-
)
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
33
|
@init_method.param_tags.each do |tag|
|
40
34
|
tag_name = tag.name
|
41
35
|
tag_text = tag.text
|
@@ -47,13 +41,13 @@ Use different names to `console_runner` be able to run #{@init_method.name} meth
|
|
47
41
|
option_name = option.pair.name.delete(':')
|
48
42
|
option_text = option.pair.text
|
49
43
|
option_type = option.pair.type
|
50
|
-
@parser.opt(option_name.to_sym, "(Ruby class: #{option_type}) " + option_text.to_s, type:
|
44
|
+
@parser.opt(option_name.to_sym, "(Ruby class: #{option_type}) " + option_text.to_s, type: TrollopConfigurator.parse_type(option_type))
|
51
45
|
end
|
52
46
|
else
|
53
|
-
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type:
|
47
|
+
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type: TrollopConfigurator.parse_type(tag_type))
|
54
48
|
end
|
55
49
|
else
|
56
|
-
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type:
|
50
|
+
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type: TrollopConfigurator.parse_type(tag_type))
|
57
51
|
end
|
58
52
|
end
|
59
53
|
end
|
@@ -76,15 +70,7 @@ Use different names to `console_runner` be able to run #{@init_method.name} meth
|
|
76
70
|
# Parse method and configure #Trollop
|
77
71
|
def parse_method(method)
|
78
72
|
ARGV.shift
|
79
|
-
@method
|
80
|
-
same_params = @method.param_tags_names & @method.option_tags_names
|
81
|
-
if same_params.count > 0
|
82
|
-
raise(
|
83
|
-
ConsoleRunnerError,
|
84
|
-
"You have the same name for @param and @option attribute(s): #{same_params.join(', ')}.
|
85
|
-
Use different names to `console_runner` be able to run #{@method.name} method."
|
86
|
-
)
|
87
|
-
end
|
73
|
+
@method = MethodParser.new method
|
88
74
|
method_params_tags = @method.param_tags
|
89
75
|
|
90
76
|
method_params_tags.each do |tag|
|
@@ -98,13 +84,13 @@ Use different names to `console_runner` be able to run #{@method.name} method."
|
|
98
84
|
option_name = option.pair.name.delete(':')
|
99
85
|
option_text = option.pair.text
|
100
86
|
option_type = option.pair.type
|
101
|
-
@parser.opt(option_name.to_sym, "(Ruby class: #{option_type}) " + option_text.to_s, type:
|
87
|
+
@parser.opt(option_name.to_sym, "(Ruby class: #{option_type}) " + option_text.to_s, type: TrollopConfigurator.parse_type(option_type))
|
102
88
|
end
|
103
89
|
else
|
104
|
-
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type:
|
90
|
+
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type: TrollopConfigurator.parse_type(tag_type))
|
105
91
|
end
|
106
92
|
else
|
107
|
-
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type:
|
93
|
+
@parser.opt(tag_name.to_sym, "(Ruby class: #{tag_type}) " + tag_text.to_s, type: TrollopConfigurator.parse_type(tag_type))
|
108
94
|
end
|
109
95
|
end
|
110
96
|
cmd_opts = Trollop::with_standard_exception_handling @parser do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: console_runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yury Karpovich
|
@@ -157,13 +157,13 @@ files:
|
|
157
157
|
- bin/setup
|
158
158
|
- console_runner.gemspec
|
159
159
|
- exe/c_run
|
160
|
-
- lib/cmd_parser.rb
|
161
160
|
- lib/console_runner.rb
|
162
161
|
- lib/console_runner/version.rb
|
163
162
|
- lib/console_runner_error.rb
|
164
163
|
- lib/file_parser.rb
|
165
164
|
- lib/method_parser.rb
|
166
165
|
- lib/runner.rb
|
166
|
+
- lib/trollop_configurator.rb
|
167
167
|
homepage: https://github.com/yuri-karpovich/console_runner
|
168
168
|
licenses:
|
169
169
|
- MIT
|