evoke 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/.travis.yml +6 -0
- data/Gemfile +2 -1
- data/README.md +71 -20
- data/Rakefile +1 -1
- data/lib/evoke.rb +4 -4
- data/lib/evoke/cli.rb +15 -14
- data/lib/evoke/comment.rb +39 -16
- data/lib/evoke/inflections.rb +3 -2
- data/lib/evoke/inflections/camelize.rb +36 -32
- data/lib/evoke/inflections/underscore.rb +39 -35
- data/lib/evoke/parameters.rb +12 -0
- data/lib/evoke/task.rb +14 -7
- data/lib/evoke/version.rb +1 -1
- 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: 469f902eb78d1d43894adf316bd4ec3e428a1d3e
|
4
|
+
data.tar.gz: 257b7371196e71be263e7fda29a6e319cfc4177c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da52e32aea945842bf8189c233b73005788fdafecb36a1229513533f3b75db1de124d31714ed820e09f2c8351fa72845cace43df705b50a0f4b0ea19e1a84da5
|
7
|
+
data.tar.gz: 2c382315f9b99381ac9d6854a98a94f5ce538b6006db24b73e73476cc9e0db8d56b379509ee83fa76f72432973538f22f51912d33d01af65d72a00b38fffdf10
|
data/.rubocop.yml
CHANGED
@@ -10,9 +10,22 @@ Lint/UnusedMethodArgument:
|
|
10
10
|
Style/EmptyLinesAroundClassBody:
|
11
11
|
Enabled: false
|
12
12
|
|
13
|
+
Style/TrivialAccessors:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/AlignParameters:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/Documentation:
|
20
|
+
Enabled: false
|
21
|
+
|
13
22
|
Metrics/MethodLength:
|
14
23
|
Enabled: true
|
15
24
|
Max: 15
|
16
25
|
|
17
26
|
Metrics/AbcSize:
|
18
27
|
Enabled: false
|
28
|
+
|
29
|
+
Metrics/LineLength:
|
30
|
+
Enabled: true
|
31
|
+
Max: 90
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Evoke
|
2
2
|
|
3
|
+
[![GitHub version](https://badge.fury.io/gh/travishaynes%2Fevoke.svg)](http://badge.fury.io/gh/travishaynes%2Fevoke)
|
4
|
+
[![Build Status](https://travis-ci.org/travishaynes/evoke.svg)](https://travis-ci.org/travishaynes/evoke)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/travishaynes/evoke/badges/gpa.svg)](https://codeclimate.com/github/travishaynes/evoke)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/travishaynes/evoke/badges/coverage.svg)](https://codeclimate.com/github/travishaynes/evoke)
|
7
|
+
[![Inline docs](http://inch-ci.org/github/travishaynes/evoke.svg)](http://inch-ci.org/github/travishaynes/evoke)
|
8
|
+
|
3
9
|
A lightweight, zero-dependency task tool for Ruby.
|
4
10
|
|
5
11
|
## Installation
|
@@ -13,36 +19,45 @@ A lightweight, zero-dependency task tool for Ruby.
|
|
13
19
|
Evoke tasks are Ruby classes that look like this:
|
14
20
|
|
15
21
|
```ruby
|
22
|
+
# Prints a friendly message to the console.
|
23
|
+
#
|
24
|
+
# This comment actually does something. The first line is used as a short
|
25
|
+
# description when `evoke help` or `evoke` is called without any arguments.
|
26
|
+
# The rest of the comment is printed, along with the first line, when
|
27
|
+
# `evoke help hello_world` is called to pull up help about this specific task.
|
16
28
|
class HelloWorld < Evoke::Task
|
17
|
-
# This description appears when your run `evoke` without any arguments.
|
18
|
-
desc "Prints a friendly message"
|
19
29
|
|
20
|
-
#
|
30
|
+
# The initializer of an Evoke::Task cannot have any required parameters.
|
31
|
+
def initialize
|
32
|
+
end
|
33
|
+
|
34
|
+
# Called when this method is invoked on the command-line. This task would be
|
35
|
+
# invoked using `evoke hello_world`.
|
21
36
|
def invoke
|
22
37
|
puts "Hello world!"
|
23
38
|
end
|
24
39
|
end
|
25
40
|
```
|
26
41
|
|
27
|
-
**Important:** Initializers for Evoke::Tasks cannot have any required arguments.
|
28
|
-
|
29
|
-
This task would be invoked from the command-line with `evoke hello_world`.
|
30
|
-
|
31
42
|
#### Namespacing
|
32
43
|
|
33
44
|
Tasks are namespaced using modules. Their command names are underscored from
|
34
45
|
their Ruby class names. For example, a task named `Example::HelloWorld` would be
|
35
46
|
invoked on the command line with `evoke example/hello_world`.
|
36
47
|
|
37
|
-
#### Command-
|
48
|
+
#### Command-Line Arguments
|
38
49
|
|
39
50
|
Here's an example of a task that uses command-line arguments and is namespaced.
|
40
51
|
|
41
52
|
```ruby
|
42
53
|
module Math
|
43
54
|
class Add < Evoke::Task
|
55
|
+
# This can be used as an alternative to providing the short description in
|
56
|
+
# the class comment.
|
44
57
|
desc "Adds two integers and prints the result in the console"
|
45
58
|
|
59
|
+
# All parameters come through as strings since they are read from the
|
60
|
+
# arguments supplied on the command-line.
|
46
61
|
def invoke(a, b)
|
47
62
|
puts a.to_i + b.to_i
|
48
63
|
end
|
@@ -50,19 +65,50 @@ module Math
|
|
50
65
|
end
|
51
66
|
```
|
52
67
|
|
53
|
-
**Note:** All arguments come through as strings since they are read from the
|
54
|
-
command-line.
|
55
|
-
|
56
68
|
This task would be invoked from the command-line with `evoke math/add 5 10`,
|
57
69
|
where a=5 and b=10 in this example.
|
58
70
|
|
59
|
-
|
60
|
-
|
71
|
+
#### Optional Arguments
|
72
|
+
|
73
|
+
Variable-assigned optional parameters are supported. Key based, `&block` and
|
74
|
+
`*` parameters are not and will raise an error.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
# SUPPORTED
|
78
|
+
def invoke(req, opt='optional argument'); end
|
79
|
+
|
80
|
+
# NOT SUPPORTED - errors will be raised
|
81
|
+
def invoke(opt: 'optional argument'); end
|
82
|
+
def invoke(*args); end
|
83
|
+
def invoke(&block); end
|
84
|
+
```
|
85
|
+
|
86
|
+
|
87
|
+
#### Named Arguments
|
88
|
+
|
89
|
+
Environment variables are used for named arguments. Make sure to document the
|
90
|
+
required environment variables in the class comment of the task, perhaps even
|
91
|
+
including some examples. Normal parameters are displayed in the tasks' help,
|
92
|
+
environment variables are not.
|
93
|
+
|
94
|
+
Here's an example of the `math/add` task from earlier using named arguments that
|
95
|
+
is well documented:
|
61
96
|
|
62
97
|
```ruby
|
63
98
|
module Math
|
99
|
+
# Adds two integers and prints the result in the console.
|
100
|
+
#
|
101
|
+
# Two environment variables are required to use this task: A and B.
|
102
|
+
#
|
103
|
+
# == Example: Adding 5 and 10.
|
104
|
+
#
|
105
|
+
# evoke math/add A=5 B=10
|
106
|
+
#
|
107
|
+
# == Example: Adding 2 and 3.
|
108
|
+
#
|
109
|
+
# evoke math/add A=2 B=3
|
110
|
+
#
|
64
111
|
class Add < Evoke::Task
|
65
|
-
desc "Adds two integers and prints the result in the console"
|
66
112
|
|
67
113
|
def initialize
|
68
114
|
@a = ENV['A'].to_i
|
@@ -76,15 +122,15 @@ module Math
|
|
76
122
|
end
|
77
123
|
```
|
78
124
|
|
79
|
-
|
80
|
-
|
81
|
-
#### Syntax Usage
|
125
|
+
#### Documenting Tasks
|
82
126
|
|
83
127
|
Using `evoke help` will give the user a more detailed description on how to use
|
84
128
|
the task. Providing this description is as easy as adding a comment to the
|
85
129
|
task's class. For example:
|
86
130
|
|
87
131
|
```ruby
|
132
|
+
# Prints the sum of two integers.
|
133
|
+
#
|
88
134
|
# This is a completely useless task that allows you to add two numbers together
|
89
135
|
# in the console using Evoke, a command-line task tool for Ruby.
|
90
136
|
#
|
@@ -94,17 +140,22 @@ task's class. For example:
|
|
94
140
|
#
|
95
141
|
# This comment is displayed for this task when you run `evoke help add`.
|
96
142
|
class Add < Evoke::Task
|
97
|
-
desc "Prints the sum of two integers."
|
98
|
-
|
99
143
|
def invoke(a, b)
|
100
144
|
puts a.to_i + b.to_i
|
101
145
|
end
|
102
146
|
end
|
103
147
|
```
|
104
148
|
|
105
|
-
Alternately, you can use the
|
149
|
+
Alternately, you can use the `#syntax` and `#desc` class methods, which will
|
150
|
+
take precedence over the class comment.
|
106
151
|
|
107
152
|
```ruby
|
153
|
+
# This class comment will not be used to display help for this task because both
|
154
|
+
# the short and long descriptions are provided using #desc and #syntax.
|
155
|
+
#
|
156
|
+
# If only the #syntax method was used, the first line of this comment would
|
157
|
+
# still be used for the short description, and vice-versa. Both methods need to
|
158
|
+
# be used to completely disregard this comment.
|
108
159
|
class Add < Evoke::Task
|
109
160
|
desc "Prints the sum of two integers."
|
110
161
|
syntax "Provide two integers as arguments to this task."
|
data/Rakefile
CHANGED
data/lib/evoke.rb
CHANGED
@@ -10,7 +10,7 @@ module Evoke
|
|
10
10
|
#
|
11
11
|
# @return [Array] The task classes.
|
12
12
|
def tasks
|
13
|
-
ObjectSpace.each_object(Class).select {|klass| klass < Evoke::Task }
|
13
|
+
ObjectSpace.each_object(Class).select { |klass| klass < Evoke::Task }
|
14
14
|
end
|
15
15
|
|
16
16
|
# Finds a task with the supplied name.
|
@@ -22,7 +22,7 @@ module Evoke
|
|
22
22
|
# Evoke.find_task('example/hello_world') # => Example::HelloWorld
|
23
23
|
#
|
24
24
|
def find_task(name)
|
25
|
-
tasks.find {|task| task.to_s == name.camelize }
|
25
|
+
tasks.find { |task| task.to_s == name.camelize }
|
26
26
|
end
|
27
27
|
|
28
28
|
# Loads all the Evoke tasks in the supplied path.
|
@@ -45,7 +45,7 @@ module Evoke
|
|
45
45
|
path = File.expand_path(path)
|
46
46
|
end
|
47
47
|
|
48
|
-
Dir[File.join(path,
|
48
|
+
Dir[File.join(path, '**', '*_task.rb')].each { |f| load f }
|
49
49
|
end
|
50
50
|
|
51
51
|
# Adds a code block that will be called before the task is invoked.
|
@@ -84,7 +84,7 @@ module Evoke
|
|
84
84
|
# @param [Evoke::Task] task The task instance that is being invoked.
|
85
85
|
# @param [Array] args The arguments that are being passed to the task.
|
86
86
|
def call_before_hooks(task, *args)
|
87
|
-
Array(@before_hooks).each {|hook| hook.call(task, *args) }
|
87
|
+
Array(@before_hooks).each { |hook| hook.call(task, *args) }
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
data/lib/evoke/cli.rb
CHANGED
@@ -13,9 +13,9 @@ module Evoke
|
|
13
13
|
def start
|
14
14
|
load_tasks
|
15
15
|
|
16
|
+
return no_tasks if tasks.empty?
|
16
17
|
return usage if @command.nil?
|
17
|
-
|
18
|
-
return syntax if @command == "help"
|
18
|
+
return syntax if @command == 'help'
|
19
19
|
|
20
20
|
task = Evoke.find_task(@command) unless @command.nil?
|
21
21
|
|
@@ -24,6 +24,8 @@ module Evoke
|
|
24
24
|
Evoke.invoke(task, *@arguments)
|
25
25
|
end
|
26
26
|
|
27
|
+
private
|
28
|
+
|
27
29
|
# Prints the syntax usage of the task requested by help.
|
28
30
|
def syntax
|
29
31
|
return usage if @arguments.empty?
|
@@ -35,24 +37,26 @@ module Evoke
|
|
35
37
|
return unknown_command if task.nil?
|
36
38
|
|
37
39
|
task.print_syntax
|
40
|
+
|
41
|
+
exit(2)
|
38
42
|
end
|
39
43
|
|
40
44
|
# Prints the usage for all the discovered tasks.
|
41
45
|
def usage
|
42
|
-
|
43
|
-
|
46
|
+
grouped_tasks = task_names.group_by(&:size)
|
47
|
+
name_sizes = grouped_tasks.keys
|
48
|
+
biggest_name = name_sizes.max || 0
|
49
|
+
tasks.each { |task| task.print_usage(biggest_name + 2) }
|
44
50
|
|
45
51
|
exit(2)
|
46
52
|
end
|
47
53
|
|
48
|
-
private
|
49
|
-
|
50
54
|
# Gets the path for the local evoke.rb file. This doesn't check if the file
|
51
55
|
# actually exists, it only returns the location where it might be.
|
52
56
|
#
|
53
57
|
# @return [String] The path for the evoke file.
|
54
58
|
def evoke_file
|
55
|
-
@evoke_file = File.join(Dir.pwd,
|
59
|
+
@evoke_file = File.join(Dir.pwd, 'evoke.rb')
|
56
60
|
end
|
57
61
|
|
58
62
|
# Loads the Evoke tasks. This will first search for a file named `evoke.rb`
|
@@ -63,21 +67,18 @@ module Evoke
|
|
63
67
|
return load(evoke_file) if File.file?(evoke_file)
|
64
68
|
|
65
69
|
# Load the tasks from the current working directory.
|
66
|
-
Evoke.load_tasks(
|
67
|
-
|
68
|
-
# No reason to continue if there are no tasks to work with.
|
69
|
-
return no_tasks if tasks.empty?
|
70
|
+
Evoke.load_tasks('lib/tasks')
|
70
71
|
end
|
71
72
|
|
72
73
|
# Tells the user there are no tasks to invoke and exits with status 1.
|
73
74
|
def no_tasks
|
74
|
-
|
75
|
+
$stderr.puts 'No tasks found in the current working directory.'
|
75
76
|
exit(1)
|
76
77
|
end
|
77
78
|
|
78
79
|
# Tells the user that the supplied task could not be found.
|
79
80
|
def unknown_command
|
80
|
-
|
81
|
+
$stderr.puts "No task named #{@command.inspect}"
|
81
82
|
exit(1)
|
82
83
|
end
|
83
84
|
|
@@ -93,7 +94,7 @@ module Evoke
|
|
93
94
|
#
|
94
95
|
# @return [Array] The name of all the tasks.
|
95
96
|
def task_names
|
96
|
-
@task_names ||= tasks.map {|task| task.name.underscore }
|
97
|
+
@task_names ||= tasks.map { |task| task.name.underscore }
|
97
98
|
end
|
98
99
|
end
|
99
100
|
end
|
data/lib/evoke/comment.rb
CHANGED
@@ -7,33 +7,54 @@ module Evoke
|
|
7
7
|
# # comment that will be read.
|
8
8
|
# class HelloWorld
|
9
9
|
# extend Evoke::Comment
|
10
|
+
#
|
11
|
+
# def a_method
|
12
|
+
# # this won't work without at least one non-inherited method
|
13
|
+
# end
|
10
14
|
# end
|
11
15
|
#
|
12
16
|
# HelloWorld.class_comment # => the multi-line comment before the class
|
13
17
|
#
|
14
18
|
module Comment
|
15
19
|
# Extracts the comment prefixing a class.
|
16
|
-
#
|
20
|
+
# @note At least one non-inherited method needs to be present in the class.
|
17
21
|
# @return [String] The class' comment.
|
18
22
|
def class_comment
|
19
|
-
|
23
|
+
@class_comment ||= defined_methods.empty? ? '' : extract_class_comment
|
24
|
+
end
|
20
25
|
|
21
|
-
|
26
|
+
private
|
22
27
|
|
23
|
-
|
24
|
-
|
28
|
+
# Reads the class's file and extracts the comment of the class that extends
|
29
|
+
# this module.
|
30
|
+
#
|
31
|
+
# @return [String] The multi-line string before the class.
|
32
|
+
def extract_class_comment
|
33
|
+
bottom_line, lines = start_index_and_code_lines
|
25
34
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
35
|
+
comment = []
|
36
|
+
|
37
|
+
(bottom_line - 1).downto(0).each do |i|
|
38
|
+
line = parse_comment_line(lines[i])
|
39
|
+
break if line == false
|
40
|
+
comment << line
|
31
41
|
end
|
32
42
|
|
33
|
-
comment.reverse.join("\n")
|
43
|
+
comment.reverse.join("\n").strip
|
34
44
|
end
|
35
45
|
|
36
|
-
|
46
|
+
# Parses a line of code and extracts the comment if present.
|
47
|
+
#
|
48
|
+
# @param [String] line The line of code to parse.
|
49
|
+
# @return [NilClass] if the line is empty.
|
50
|
+
# @return [Boolean] false if the line is not a comment.
|
51
|
+
# @return [String] The extracted comment, without the prefixed # tag.
|
52
|
+
# @private
|
53
|
+
def parse_comment_line(line)
|
54
|
+
line = line.strip
|
55
|
+
return if line.empty?
|
56
|
+
line.start_with?('#') ? line[1..line.length].strip : false
|
57
|
+
end
|
37
58
|
|
38
59
|
# Gets the lines in the class file and the line number that the class is
|
39
60
|
# actually defined.
|
@@ -68,10 +89,12 @@ module Evoke
|
|
68
89
|
# @return [Array] The source locations of every method in the class.
|
69
90
|
# @private
|
70
91
|
def defined_methods
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
92
|
+
@defined_methods ||= begin
|
93
|
+
methods = methods(false).map { |m| method(m) }
|
94
|
+
methods += instance_methods(false).map { |m| instance_method(m) }
|
95
|
+
methods.map!(&:source_location)
|
96
|
+
methods.compact
|
97
|
+
end
|
75
98
|
end
|
76
99
|
end
|
77
100
|
end
|
data/lib/evoke/inflections.rb
CHANGED
@@ -3,9 +3,10 @@ module Evoke
|
|
3
3
|
# different purposes.
|
4
4
|
module Inflections
|
5
5
|
# Load the inflections.
|
6
|
-
|
6
|
+
inflections_path = File.expand_path('../inflections/*.rb', __FILE__)
|
7
|
+
Dir[inflections_path].each { |f| require f }
|
7
8
|
|
8
9
|
# Add the inflections to the String class.
|
9
|
-
constants.each {|i| String.send(:include, const_get(i)) }
|
10
|
+
constants.each { |i| String.send(:include, const_get(i)) }
|
10
11
|
end
|
11
12
|
end
|
@@ -1,35 +1,39 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
1
|
+
module Evoke
|
2
|
+
module Inflections
|
3
|
+
# String inflections for converting to CamelCase.
|
4
|
+
#
|
5
|
+
# Camelizing a string takes all the compound words separated by an underscore
|
6
|
+
# and combines them together, capitalizing the first letter of each word. It
|
7
|
+
# also converts '/' to '::'. For example "hello_world" is camelized to
|
8
|
+
# "HelloWorld", and "hello/world" is camelized to "Hello::World".
|
9
|
+
module Camelize
|
10
|
+
# Converts a string to CamelCase. It also converts '/' to '::'.
|
11
|
+
#
|
12
|
+
# @example Camelize the string "example/hello_world".
|
13
|
+
#
|
14
|
+
# "example/hello_world".camelize # => "Example::HelloWorld"
|
15
|
+
#
|
16
|
+
# @return [String] The CamelCase string.
|
17
|
+
def camelize
|
18
|
+
dup.tap do |s|
|
19
|
+
s.capitalize!
|
20
|
+
s.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
21
|
+
s.gsub!('/', '::')
|
22
|
+
end
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
# Replaces the existing String instance with a CamelCase string.
|
26
|
+
#
|
27
|
+
# @example Camelizing the string "example/hello_world".
|
28
|
+
#
|
29
|
+
# string = "example/hello_world"
|
30
|
+
# string.camelize!
|
31
|
+
# string # => "Example::HelloWorld"
|
32
|
+
#
|
33
|
+
# @return [String] This string modified to CamelCase.
|
34
|
+
def camelize!
|
35
|
+
replace(camelize)
|
36
|
+
end
|
37
|
+
end
|
34
38
|
end
|
35
39
|
end
|
@@ -1,38 +1,42 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# string
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
module Evoke
|
2
|
+
module Inflections
|
3
|
+
# String inflections for converting to underscored form.
|
4
|
+
#
|
5
|
+
# Underscoring a string injects an underscore between CamelCase words, replaces
|
6
|
+
# all '::' with '/' and converts the string to lowercase. For example, the
|
7
|
+
# string "HelloWorld" is underscored to "hello_world", and the string
|
8
|
+
# "Hello::World" is underscored to "hello/world".
|
9
|
+
module Underscore
|
10
|
+
# Creates an underscored, lowercase form of the string and changes '::' to '/'
|
11
|
+
# to convert namespaces to paths.
|
12
|
+
#
|
13
|
+
# @example Underscoring "Example::HelloWorld".
|
14
|
+
#
|
15
|
+
# "Example::HelloWorld" # => "example/hello_world"
|
16
|
+
#
|
17
|
+
# @return [String] The underscored string.
|
18
|
+
def underscore
|
19
|
+
dup.tap do |s|
|
20
|
+
s.gsub!(/::/, '/')
|
21
|
+
s.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
22
|
+
s.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
23
|
+
s.tr!('-', '_')
|
24
|
+
s.downcase!
|
25
|
+
end
|
26
|
+
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
# Replaces the existing String instance with its underscored form.
|
29
|
+
#
|
30
|
+
# @example Underscoring the string "Example::HelloWorld".
|
31
|
+
#
|
32
|
+
# string = "Example::HelloWorld"
|
33
|
+
# string.underscore!
|
34
|
+
# string # => "example/hello_world"
|
35
|
+
#
|
36
|
+
# @return [String] This underscored form of the original string.
|
37
|
+
def underscore!
|
38
|
+
replace(underscore)
|
39
|
+
end
|
40
|
+
end
|
37
41
|
end
|
38
42
|
end
|
data/lib/evoke/parameters.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
module Evoke
|
2
2
|
# Extendable module for providing access to method parameters during runtime.
|
3
3
|
module Parameters
|
4
|
+
# Finds the minimum and maximum amount of parameters the supplied method
|
5
|
+
# supports.
|
6
|
+
#
|
7
|
+
# @param [UnboundMethod] method The method to check.
|
8
|
+
# @return [Array] The first item is the minimum size, second is the maximum.
|
9
|
+
def parameter_size(method)
|
10
|
+
req_size = required_parameters(method).size
|
11
|
+
opt_size = optional_parameters(method).size
|
12
|
+
|
13
|
+
[req_size, req_size + opt_size]
|
14
|
+
end
|
15
|
+
|
4
16
|
# Gets all the required parameters for a method.
|
5
17
|
#
|
6
18
|
# @param [UnboundMethod] method The method to scan.
|
data/lib/evoke/task.rb
CHANGED
@@ -9,8 +9,11 @@ module Evoke
|
|
9
9
|
# @param [Integer] name_col_size The size of the name column.
|
10
10
|
# @private
|
11
11
|
def print_usage(name_col_size)
|
12
|
+
description = "#{@desc || class_comment}".split("\n")[0]
|
13
|
+
description ||= 'No description available.'
|
14
|
+
|
12
15
|
$stdout.print name.underscore.ljust(name_col_size)
|
13
|
-
$stdout.puts "# #{
|
16
|
+
$stdout.puts "# #{description}"
|
14
17
|
end
|
15
18
|
|
16
19
|
# Prints the syntax usage for this task to the console.
|
@@ -31,7 +34,7 @@ module Evoke
|
|
31
34
|
# @param [String] value The description. Keep it short!
|
32
35
|
# @return [String] The supplied description.
|
33
36
|
def desc(value)
|
34
|
-
value +=
|
37
|
+
value += '.' unless value.end_with?('.')
|
35
38
|
@desc = value
|
36
39
|
end
|
37
40
|
|
@@ -61,13 +64,17 @@ module Evoke
|
|
61
64
|
# @return nil if the validation passes.
|
62
65
|
# @private
|
63
66
|
def validate_arguments(arguments)
|
64
|
-
|
65
|
-
|
67
|
+
invoke_method = instance_method(:invoke)
|
68
|
+
min, max = parameter_size(invoke_method)
|
69
|
+
|
70
|
+
size = Array(arguments).size
|
71
|
+
return if size >= min && size <= max
|
72
|
+
|
73
|
+
e_size = min == max ? min : "#{min}..#{max}"
|
66
74
|
|
67
|
-
|
75
|
+
$stderr.print 'Wrong number of arguments. '
|
76
|
+
$stderr.print "Received #{size} instead of #{e_size}.\n"
|
68
77
|
|
69
|
-
$stderr.print "Wrong number of arguments. "
|
70
|
-
$stderr.print "Received #{a_size} instead of #{e_size}.\n"
|
71
78
|
exit(1)
|
72
79
|
end
|
73
80
|
end
|
data/lib/evoke/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evoke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Travis Haynes
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|