bales 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8545457d99fcc8ad1f955a400e85117f9232bafb
4
- data.tar.gz: 6b071c4698777e472fbced6eac86c5c4ecf398c4
3
+ metadata.gz: 17750f3056694dcabc3be1c2ac111978e179043f
4
+ data.tar.gz: b6087e538fd4eccb2e614b1dbd539cf4058b5e90
5
5
  SHA512:
6
- metadata.gz: e993e329e43ce41ee9388ccc0e6fe4170df541b0545a699bbfdab237768e69bace8b8e1b8198756403d387430b897d4ea0ffbaff0c80e5b842b70cf7b8d4df39
7
- data.tar.gz: 0c8ae1f87771e60d703be9338c8438bc529acfd85ed2bb43b5f5fd706ac08c0ba397f14bcd2ee7093742ec0557398a4995b5ad4ca2fdd323bae35e8c6e25bab0
6
+ metadata.gz: 05e0241f93ac005d784ca7d66bc806de2e5ef609c947bf69c1cdbbd338512f6c6170697f47561a6476ac40084e02a958caf1f3da1cba73fb230a575de5347c51
7
+ data.tar.gz: 31421e16c924c9dfc59318117c9c597f51a31925c7b75bc43248613fa4505f57888cdb0f33e7eb456ab7c5fcdac76f416e5ca158404836e99ae3d20a978b8511
@@ -174,10 +174,14 @@ module Bales
174
174
  .map { |p| p.capitalize }
175
175
  .join
176
176
  name = "#{const}::#{part}"
177
- if const.const_defined? name
178
- const = eval(name)
179
- depth += 1
180
- else
177
+ begin
178
+ if const.const_defined? name
179
+ const = eval(name)
180
+ depth += 1
181
+ else
182
+ break
183
+ end
184
+ rescue NameError
181
185
  break
182
186
  end
183
187
  end
@@ -41,8 +41,13 @@ class Bales::Command::Help < Bales::Command
41
41
  end
42
42
 
43
43
  ns.constants
44
- .select { |c| ns.const_defined? "#{ns}::#{c}" }
45
- .select { |c| eval("#{ns}::#{c}").class == Class }
44
+ .select { |c|
45
+ begin
46
+ ns.const_defined? "#{ns}::#{c}"
47
+ rescue NameError
48
+ false
49
+ end
50
+ }.select { |c| eval("#{ns}::#{c}").class == Class }
46
51
  .select { |c| eval("#{ns}::#{c}") <= Bales::Command }
47
52
  .map { |c| eval "#{ns}::#{c}" }
48
53
  end
@@ -1,3 +1,3 @@
1
1
  module Bales
2
- VERSION="0.1.1"
2
+ VERSION="0.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bales
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan S. Northrup
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-18 00:00:00.000000000 Z
11
+ date: 2015-09-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A framework for building command-line applications
14
14
  email:
@@ -19,15 +19,10 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - README.md
21
21
  - lib/bales.rb
22
- - lib/bales.rb~
23
22
  - lib/bales/application.rb
24
- - lib/bales/application.rb~
25
23
  - lib/bales/command.rb
26
- - lib/bales/command.rb~
27
24
  - lib/bales/command/help.rb
28
- - lib/bales/command/help.rb~
29
25
  - lib/bales/version.rb
30
- - lib/bales/version.rb~
31
26
  homepage: http://github.com/YellowApple/bales
32
27
  licenses:
33
28
  - MIT
@@ -38,17 +33,17 @@ require_paths:
38
33
  - lib
39
34
  required_ruby_version: !ruby/object:Gem::Requirement
40
35
  requirements:
41
- - - ">="
36
+ - - '>='
42
37
  - !ruby/object:Gem::Version
43
38
  version: '0'
44
39
  required_rubygems_version: !ruby/object:Gem::Requirement
45
40
  requirements:
46
- - - ">="
41
+ - - '>='
47
42
  - !ruby/object:Gem::Version
48
43
  version: '0'
49
44
  requirements: []
50
45
  rubyforge_project:
51
- rubygems_version: 2.4.6
46
+ rubygems_version: 2.4.8
52
47
  signing_key:
53
48
  specification_version: 4
54
49
  summary: Ruby on Bales
@@ -1,236 +0,0 @@
1
- # :main: README.md
2
-
3
- ##
4
- # Ruby on Bales (or just "Bales" for short) is to command-line apps what
5
- # Ruby on Rails (or just "Rails" for short) is to websites/webapps.
6
- #
7
- # The name (and concept) was shamelessly stolen from Jason R. Clark's
8
- # "Testing the Multiverse" talk at Ruby on Ales 2015. Here's to hoping that
9
- # we, as a Ruby programming community, can get a headstart on a command-line
10
- # app framework *before* the Puma-Unicorn Wars ravage the Earth.
11
- module Bales
12
- ##
13
- # Base class for Bales apps. Your command-line program should create a
14
- # subclass of this, then call said subclass' #parse_and_run instance
15
- # method, like so:
16
- #
17
- # ```ruby
18
- # class MyApp::Application < Bales::Application
19
- # # insert customizations here
20
- # end
21
- #
22
- # MyApp::Application.parse_and_run
23
- # ```
24
- class Application
25
- ##
26
- # Runs the specified command (should be a valid class; preferably, should
27
- # be a subclass of Bales::Command). Takes a list of positional args
28
- # followed by named options.
29
- def self.run(command=Bales::Command::Help, *args, **opts)
30
- command.run *args, **opts
31
- end
32
-
33
- ##
34
- # Parses ARGV (or some other array if you specify one), returning the
35
- # class of the identified command, a hash containing the passed-in
36
- # options, and a list of any remaining arguments
37
- def self.parse(argv=ARGV)
38
- command, result = parse_command_name argv.dup
39
- opts, args = command.parse_opts result
40
- return command, args, opts
41
- end
42
-
43
- ##
44
- # Parses ARGV (or some other array if you specify one) for a command to
45
- # run and its arguments/options, then runs the command.
46
- def self.parse_and_run(argv=ARGV)
47
- command, args, opts = parse argv
48
- run command, *args, **opts
49
- end
50
-
51
- private
52
-
53
- def parse_command_name(argv)
54
- command_name_parts = []
55
- argv.each do |arg|
56
- last if arg.match(/^-/)
57
- test = args_to_constant [*command_name_parts, arg]
58
- if eval("defined? #{test}") == "constant"
59
- command_name_parts.push argv.shift
60
- else
61
- last
62
- end
63
- end
64
- command = args_to_constant [*command_name_parts, arg]
65
- command, argv
66
- end
67
-
68
- def args_to_constant(argv)
69
- result = argv.dup
70
- result.map! do |arg|
71
- arg.capitalize
72
- arg.gsub('-','_').split('_').map { |e| e.capitalize}.join
73
- end
74
- result.join('::')
75
- end
76
- end
77
-
78
- ##
79
- # Base class for all Bales commands. Subclass this class to create your
80
- # own command, like so:
81
- #
82
- # ```ruby
83
- # class MyApp::Command::Hello < Bales::Command
84
- # def self.run(*args, **opts)
85
- # puts "Hello, world!"
86
- # end
87
- # end # produces a `my-app hello` command that prints "Hello, world!"
88
- # ```
89
- #
90
- # Note that the above will accept any number of arguments (including none
91
- # at all!). If you want to change this behavior, change `self.run`'s
92
- # signature, like so:
93
- #
94
- # ```ruby
95
- # class MyApp::Command::Smack < Bales::Command
96
- # def self.run(target, **opts)
97
- # puts "#{target} has been smacked with a large trout"
98
- # end
99
- # end
100
- # ```
101
- #
102
- # Subcommands are automatically derived from namespacing, like so:
103
- #
104
- # ```ruby
105
- # class MyApp::Command::Foo::Bar < Bales::Command
106
- # def self.run(*args, **opts)
107
- # # ...
108
- # end
109
- # end # produces `my-app foo bar`
110
- # ```
111
- #
112
- # Camel-cased command classes can be accessed using either hyphenation or
113
- # underscores, like so:
114
- #
115
- # ```ruby
116
- # class MyApp::Command::FooBarBaz < Bales::Command
117
- # # ...
118
- # end
119
- # # valid result: "my-app foo-bar-baz"
120
- # # also valid: "my-app foo_bar_baz"
121
- # ```
122
- class Command
123
- @options = {}
124
-
125
- ##
126
- # Runs the command with the provided list of arguments and named options.
127
- # Your command should override this method (which by default does
128
- # nothing), since this is the method that `Bales::Application.run` calls
129
- # in order to actually run your command.
130
- #
131
- # For example:
132
- #
133
- # ```ruby
134
- # class MyApp::Command::Hello < Bales::Command
135
- # def self.run(*args, **opts)
136
- # puts "Hello, world!"
137
- # end
138
- # end
139
- # ```
140
- def self.run(*args, **opts)
141
- end
142
-
143
- ##
144
- # Defines a named option that the command will accept, along with some
145
- # named arguments:
146
- #
147
- # `:short_form` (optional)
148
- # : A shorthand flag to use for the option (like `-v`). This should be a
149
- # string, like `"-v"`.
150
- #
151
- # `:long_form` (optional)
152
- # : A longhand flag to use for the option (like `--verbose`). This is
153
- # derived from the name of the option if not specified. This should be
154
- # a string, like `"--verbose"`
155
- #
156
- # `:type` (optional)
157
- # : The type that this option represents. Defaults to `TrueClass` if
158
- # `:arg` is not specified; else, defaults to `String`. This must be a
159
- # valid class name.
160
- #
161
- # A special note on boolean options: if you want your boolean to
162
- # default to `true`, set `:type` to `TrueClass`. Likewise, if you want
163
- # it to default to `false`, set `:type` to `FalseClass`.
164
- #
165
- # `:arg` (required unless `:type` is `TrueClass` or `FalseClass`)
166
- # : The name of the argument this option accepts. This must not be
167
- # defined if `:type` is either `TrueClass` or `FalseClass`; for all
168
- # other types, this must be specified. As mentioned above, though, if
169
- # `:type` is unspecified, the existence of `:arg` then determines
170
- # whether the option's `:type` should default to `TrueClass` or
171
- # `String`. This should be a symbol, like `:level`.
172
- #
173
- # Aside from the hash of option-options, `option` takes a single `name`
174
- # argument, which should be a symbol representing the name of the option
175
- # to be set, like `:verbose`.
176
- def self.option(name, **opts)
177
- name = name.to_sym
178
- opts[:long_form] ||= "--#{name.to_s}".gsub("_","-")
179
-
180
- unless opts[:type].class == Class
181
- raise ArgumentError, ":type option should be a valid class"
182
- end
183
-
184
- if opts[:type] == TrueClass or opts[:type] == FalseClass
185
- raise ArgumentError, ":arg in boolean opt" unless opts[:arg].nil?
186
- else
187
- raise ArgumentError, "missing :arg" if opts[:arg].nil?
188
- end
189
-
190
- @options[name] = opts
191
- end
192
-
193
- ##
194
- # Takes an ARGV-like array and returns a hash of options and what's left
195
- # of the original array. This is rarely needed for normal use, but is
196
- # an integral part of how a Bales::Application parses the ARGV it
197
- # receives.
198
- #
199
- # Normally, this should be perfectly fine to leave alone, but if you
200
- # prefer to define your own parsing method (e.g. if you want to specify
201
- # an alternative format for command-line options, or you are otherwise
202
- # dissatisfied with the default approach of wrapping OptionParser), this
203
- # is the method you'd want to override.
204
- def self.parse_opts(argv)
205
- optparser = OptionParser.new
206
- result = {}
207
- @options.each do |name, opts|
208
- result[name] = opts[:default]
209
- parser_args = []
210
- parser_args.push opts[:short_form]
211
- parser_args.push opts[:long_form]
212
- unless opts[:type] == TrueClass or opts[:type] == FalseClass
213
- parser_args.push opts[:type]
214
- end
215
- parser_args.push opts[:description]
216
-
217
- if opts[:type] == FalseClass
218
- optparser.on(*parser_args) do |value|
219
- result[name] = !value
220
- end
221
- else
222
- optparser.on(*parser_args) do |value|
223
- result[name] = value
224
- end
225
- end
226
- end
227
- end
228
- end
229
-
230
- class Command::Help < Command
231
- def self.run(*args, **opts)
232
- puts "This will someday output some help text"
233
-
234
- end
235
- end
236
- end
@@ -1,71 +0,0 @@
1
- ##
2
- # Base class for Bales apps. Your command-line program should create a
3
- # subclass of this, then call said subclass' #parse_and_run instance
4
- # method, like so:
5
- #
6
- # ```ruby
7
- # class MyApp::Application < Bales::Application
8
- # # insert customizations here
9
- # end
10
- #
11
- # MyApp::Application.parse_and_run
12
- # ```
13
- class Bales::Application
14
- @default_command = Bales::Command::Help
15
- def self.default(command=Bales::Command::Help)
16
- @default_command = command
17
- end
18
-
19
- ##
20
- # Runs the specified command (should be a valid class; preferably, should
21
- # be a subclass of Bales::Command). Takes a list of positional args
22
- # followed by named options.
23
- def self.run(command, *args, **opts)
24
- command.run *args, **opts
25
- end
26
-
27
- ##
28
- # Parses ARGV (or some other array if you specify one), returning the
29
- # class of the identified command, a hash containing the passed-in
30
- # options, and a list of any remaining arguments
31
- def self.parse(argv=ARGV)
32
- command, result = parse_command_name argv.dup
33
- command ||= @default_command
34
- opts, args = command.parse_opts result
35
- return command, args, opts
36
- end
37
-
38
- ##
39
- # Parses ARGV (or some other array if you specify one) for a command to
40
- # run and its arguments/options, then runs the command.
41
- def self.parse_and_run(argv=ARGV)
42
- command, args, opts = parse argv
43
- run command, *args, **opts
44
- end
45
-
46
- private
47
-
48
- def self.parse_command_name(argv)
49
- command_name_parts = []
50
- argv.each do |arg|
51
- last if arg.match(/^-/)
52
- test = args_to_constant [*command_name_parts, arg]
53
- if eval("defined? #{test}") == "constant"
54
- command_name_parts.push argv.shift
55
- else
56
- last
57
- end
58
- end
59
- command = args_to_constant [*command_name_parts]
60
- return command, argv
61
- end
62
-
63
- def self.args_to_constant(argv)
64
- result = argv.dup
65
- result.map! do |arg|
66
- arg.capitalize
67
- arg.gsub('-','_').split('_').map { |e| e.capitalize}.join
68
- end
69
- eval result.join('::')
70
- end
71
- end
@@ -1,189 +0,0 @@
1
- ##
2
- # Base class for all Bales commands. Subclass this class to create your
3
- # own command, like so:
4
- #
5
- # ```ruby
6
- # class MyApp::Command::Hello < Bales::Command
7
- # def self.run(*args, **opts)
8
- # puts "Hello, world!"
9
- # end
10
- # end # produces a `my-app hello` command that prints "Hello, world!"
11
- # ```
12
- #
13
- # Note that the above will accept any number of arguments (including none
14
- # at all!). If you want to change this behavior, change `self.run`'s
15
- # signature, like so:
16
- #
17
- # ```ruby
18
- # class MyApp::Command::Smack < Bales::Command
19
- # def self.run(target, **opts)
20
- # puts "#{target} has been smacked with a large trout"
21
- # end
22
- # end
23
- # ```
24
- #
25
- # Subcommands are automatically derived from namespacing, like so:
26
- #
27
- # ```ruby
28
- # class MyApp::Command::Foo::Bar < Bales::Command
29
- # def self.run(*args, **opts)
30
- # # ...
31
- # end
32
- # end # produces `my-app foo bar`
33
- # ```
34
- #
35
- # Camel-cased command classes can be accessed using either hyphenation or
36
- # underscores, like so:
37
- #
38
- # ```ruby
39
- # class MyApp::Command::FooBarBaz < Bales::Command
40
- # # ...
41
- # end
42
- # # valid result: "my-app foo-bar-baz"
43
- # # also valid: "my-app foo_bar_baz"
44
- # ```
45
- class Bales::Command
46
- @options = {}
47
- def self.options
48
- @options
49
- end
50
- def self.options=(new)
51
- @options = new
52
- end
53
-
54
- ##
55
- # Assigns an action to this command. Said action is represented as a
56
- # block, which should accept an array of arguments and a hash of options.
57
- # For example:
58
- #
59
- # ```ruby
60
- # class MyApp::Hello < Bales::Command
61
- # action do |args, opts|
62
- # puts "Hello, world!"
63
- # end
64
- # end
65
- # ```
66
- def self.action(&code)
67
- @action = code
68
- end
69
-
70
- def self.run(*args, **opts)
71
- @action.call(args, opts)
72
- end
73
-
74
- ##
75
- # Defines a named option that the command will accept, along with some
76
- # named arguments:
77
- #
78
- # `:short_form` (optional)
79
- # : A shorthand flag to use for the option (like `-v`). This should be a
80
- # string, like `"-v"`.
81
- #
82
- # `:long_form` (optional)
83
- # : A longhand flag to use for the option (like `--verbose`). This is
84
- # derived from the name of the option if not specified. This should be
85
- # a string, like `"--verbose"`
86
- #
87
- # `:type` (optional)
88
- # : The type that this option represents. Defaults to `TrueClass`.
89
- # Should be a valid class name, like `String` or `Integer`
90
- #
91
- # A special note on boolean options: if you want your boolean to
92
- # default to `true`, set `:type` to `TrueClass`. Likewise, if you want
93
- # it to default to `false`, set `:type` to `FalseClass`.
94
- #
95
- # `:arg` (optional)
96
- # : The name of the argument this option accepts. This should be a
97
- # symbol (like :level) or `false` (if the option is a boolean flag).
98
- # Defaults to the name of the option or (if the option's `:type` is
99
- # `TrueClass` or `FalseClass`) `false`.
100
- #
101
- # If this is an array, and `:type` is set to `Enumerable` or some
102
- # subclass thereof, this will instead be interpreted as a list of
103
- # sample arguments during option parsing. It's recommended you set
104
- # this accordingly if `:type` is `Enumerable` or any of its subclasses.
105
- #
106
- # `:required` (optional)
107
- # : Whether or not the option is required. This should be a boolean
108
- # (`true` or `false`). Default is `false`.
109
- #
110
- # Aside from the hash of option-options, `option` takes a single `name`
111
- # argument, which should be a symbol representing the name of the option
112
- # to be set, like `:verbose`.
113
- def self.option(name, **opts)
114
- name = name.to_sym
115
- opts[:long_form] ||= "--#{name.to_s}".gsub("_","-")
116
-
117
- unless opts[:type].is_a? Class
118
- raise ArgumentError, ":type option should be a valid class"
119
- end
120
-
121
- unless opts[:type].is_a?(TrueClass) or opts[:type].is_a?(FalseClass)
122
- opts[:arg] ||= name
123
- end
124
-
125
- # if opts[:type] == TrueClass or opts[:type] == FalseClass
126
- # raise ArgumentError, ":arg in boolean opt" unless opts[:arg].nil?
127
- # else
128
- # raise ArgumentError, "missing :arg" if opts[:arg].nil?
129
- # end
130
-
131
- result = {}
132
- result[name] = opts
133
- self.options = result
134
- end
135
-
136
- ##
137
- # Takes an ARGV-like array and returns a hash of options and what's left
138
- # of the original array. This is rarely needed for normal use, but is
139
- # an integral part of how a Bales::Application parses the ARGV it
140
- # receives.
141
- #
142
- # Normally, this should be perfectly fine to leave alone, but if you
143
- # prefer to define your own parsing method (e.g. if you want to specify
144
- # an alternative format for command-line options, or you are otherwise
145
- # dissatisfied with the default approach of wrapping OptionParser), this
146
- # is the method you'd want to override.
147
- def self.parse_opts(argv)
148
- optparser = OptionParser.new
149
- result = {}
150
- @options.each do |name, opts|
151
- result[name] = opts[:default]
152
- parser_args = []
153
- parser_args.push opts[:short_form]
154
- if opts[:type].is_a?(TrueClass) or opts[:type].is_a?(FalseClass)
155
- parser_args.push opts[:long_form]
156
- else
157
- argstring = opts[:arg].to_s.upcase
158
- if opts[:required]
159
- parser_args.push "#{opts[:long_form]} #{argstring}"
160
- else
161
- parser_args.push "#{opts[:long_form]} [#{argstring}]"
162
- parser_args.push opts[:type]
163
- end
164
- parser_args.push opts[:description]
165
-
166
- if opts[:type].is_a? FalseClass
167
- optparser.on(*parser_args) do |value|
168
- result[name] = !value
169
- end
170
- else
171
- optparser.on(*parser_args) do |value|
172
- result[name] = value
173
- end
174
- end
175
- end
176
-
177
- opt_parser.parse! argv
178
- return result, argv
179
- end
180
- end
181
- end
182
-
183
- ##
184
- # Default help command. You'll probably use your own...
185
- class Bales::Command::Help < Bales::Command
186
- action do |args, opts|
187
- puts "This will someday output some help text"
188
- end
189
- end
@@ -1,37 +0,0 @@
1
- ##
2
- # Prints help text for a given namespace
3
- class Bales::Command::Help < Bales::Command
4
- action do |args, opts|
5
- puts "This will someday output some help text"
6
- end
7
-
8
- private
9
-
10
- def commands(ns)
11
- unless eval("defined? #{ns}") == "constant"
12
- raise ArgumentError, "expected a constant, but got a #{ns.class}"
13
- end
14
-
15
- ns.constants
16
- .select { |c| eval("#{ns}::#{c}") <= Bales::Command }
17
- .map { |c| eval "#{ns}::#{c}" }
18
- end
19
-
20
- def format_option(name, opts, width=72)
21
- long = "#{opts[:long_form]}"
22
- if opts[:type] <= TrueClass or opts[:type] <= FalseClass
23
- if opts[:required]
24
- long << " #{opts[:arg]}"
25
- else
26
- long << " [#{opts[:arg]}]"
27
- end
28
- end
29
-
30
- output = "#{name} (#{opts[:type]}): "
31
- output << "#{opts[:short_form]} / " if opts[:short_form]
32
- output << long
33
- output << "\n"
34
- output << opts[:description]
35
- output
36
- end
37
- end
@@ -1,3 +0,0 @@
1
- module Bales
2
- VERSION="0.0.0"
3
- end