console_runner 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|