bales 0.0.1 → 0.0.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: a449ca597147ec6bc515f40ff54bd657662f9e80
4
- data.tar.gz: af9b1836f3d639cb968cdfba34daccd60e95ef0c
3
+ metadata.gz: 58dd5ac6bd3070bc03dc5c84db2f92c394a43fd2
4
+ data.tar.gz: dac3a1f876ae148806de122ceca026ac39db55ed
5
5
  SHA512:
6
- metadata.gz: 3dd8e473c927c35175c378f49ba43f5cd62e639ab929b50dc7f5dfe6f3f5af08a78dee252a72904071d1d737154ff94008a6348428b6857ee0073320c1e26f45
7
- data.tar.gz: eb9675b63e316b5a316991d4066b054c2698ec799ede8bf966a721de528789296b0b62643acfab94916a5a959d5f28182a5f68d89726c3a2f30bef1342233ee3
6
+ metadata.gz: 650893c15923467acaa65cb97aad581b66b8cc1dcb037f74cb9013c54887cefa2d41f39897ca06a9823a6517dc24e0caffef08862d600daf8d751be0dff97484
7
+ data.tar.gz: 4b1f685e20a94a1012ce13ea5ec1152449accd0515c452cf02c4fbdb69a83b407df67b1ad672ba540f6dd801501754a675070b4868400a46eeadb057203aa8be
data/README.md CHANGED
@@ -70,12 +70,27 @@ John has been smacked with a fish.
70
70
 
71
71
  ## So how does it work?
72
72
 
73
- A Bales app is basically a collection of classes: one class representing the application itself (`SimpleApp::Application` in the above example) and one or more classes representing the application's commands (`SimpleApp::Command` and its children in the above example).
73
+ * Come up with a name for your app, like `MyApp`
74
+ * Create an `Application` class under that namespace which inherits from `Bales::Application`
75
+ * Create a `Command` class under that namespace which inherits from `Bales::Command`
76
+ * Give that `Command` an `action`, which will be what your application does by default if no valid subcommands are passed to it
77
+ * (Optional) Create one or more classes under the `MyApp::Command` namespace, inheriting from some subclass of `Bales::Command` (including the base command you defined previously), if you want some git-style or rails-style subcommands.
78
+
79
+ Basically, a Bales app is just a bunch of classes with some fairy dust that turns them into runnable commands. Bales will check the namespace that your subclass of `Bales::Application` lives in for a `Command` namespace, then search there for available commands.
74
80
 
75
81
  The application has (or *will* have, more precisely; I don't have a whole lot for you on this front just yet) a few available DSL-ish functions for you to play with.
76
82
 
77
83
  * `version`: sets your app's version number. If you use semantic versioning, you can query this with the `major_version`, `minor_version`, and `patch_level` class methods.
78
84
 
85
+ Meanwhile, commands *also* have some DSL-ish functions to play around with.
86
+
87
+ * `option`: defines a command-line option, like `--verbose` or `-f` or something. It takes the name of the option (which becomes a key in your command's options hash) and some named parameters:
88
+ * `:type`: a valid Ruby class, like `String`. For a boolean, you should provide either `TrueClass` or `FalseClass`, which - when set - will set the option in question to `true` or `false` (respectively).
89
+ * `:short_form`: a short flag, like `'-v'`. You must specify this if you want a short flag.
90
+ * `:long_form`: a long flag, like `'--verbose'`. This will be created from the option's name if you don't override it here.
91
+ * `:description`: a quick description of the option, like `"Whether or not to be verbose"`.
92
+ * `action`: defines what the command should do when it's called. This is provided in the form of a block. Said block should accept two arguments (an array of arguments and a hash of options), though you don't *have* to name them with pipes and stuff if you know that your command won't take any arguments or options.
93
+
79
94
  ## What kind of a silly names is "Bales", anyway?
80
95
 
81
96
  It's shamelessly stolen^H^H^H^H^H^Hborrowed from Jason R. Clark's "Testing the Multiverse" talk at Ruby on Ales 2015 (which, if you haven't watched, you [totally should](http://confreaks.tv/videos/roa2015-testing-the-multiverse)). Sorry, Jason. Hope you don't mind.
@@ -2,26 +2,16 @@ require 'bales/command'
2
2
 
3
3
  ##
4
4
  # Base class for Bales apps. Your command-line program should create a
5
- # subclass of this, then call said subclass' #parse_and_run instance
5
+ # subclass of this, then call said subclass' +#parse_and_run+ instance
6
6
  # method, like so:
7
7
  #
8
- # ```ruby
9
- # class MyApp::Application < Bales::Application
10
- # # insert customizations here
11
- # end
8
+ # class MyApp::Application < Bales::Application
9
+ # # insert customizations here
10
+ # end
12
11
  #
13
- # MyApp::Application.parse_and_run
14
- # ```
12
+ # MyApp::Application.parse_and_run
15
13
  module Bales
16
14
  class Application
17
- def self.default_command
18
- @default_command ||= Bales::Command::Help
19
- @default_command
20
- end
21
- def self.default_command=(command)
22
- @default_command = command
23
- end
24
-
25
15
  ##
26
16
  # Set or retrieve the application's version number. Defaults to "0.0.0".
27
17
  def self.version(v="0.0.0")
@@ -51,7 +41,7 @@ module Bales
51
41
 
52
42
  ##
53
43
  # Runs the specified command (should be a valid class; preferably, should
54
- # be a subclass of Bales::Command). Takes a list of positional args
44
+ # be a subclass of +Bales::Command+). Takes a list of positional args
55
45
  # followed by named options.
56
46
  def self.run(command, *args, **opts)
57
47
  command.run *args, **opts
@@ -78,26 +68,6 @@ module Bales
78
68
 
79
69
  private
80
70
 
81
- # def self.parse_command_name(argv)
82
- # command_name_parts = [*constant_to_args(base_name), "command"]
83
- # puts command_name_parts
84
- # argv.each do |arg|
85
- # break if arg.match(/^-/)
86
- # begin
87
- # test = args_to_constant [*command_name_parts, arg]
88
- # rescue NameError
89
- # break
90
- # end
91
- # if eval("defined? #{test}") == "constant"
92
- # command_name_parts.push argv.shift
93
- # else
94
- # break
95
- # end
96
- # end
97
- # command = args_to_constant [*command_name_parts]
98
- # return command, argv
99
- # end
100
-
101
71
  def self.parse_command_name(argv)
102
72
  command_name_parts = [*constant_to_args(base_name), "command"]
103
73
  depth = 0
data/lib/bales/command.rb CHANGED
@@ -4,52 +4,50 @@ require 'optparse'
4
4
  # Base class for all Bales commands. Subclass this class to create your
5
5
  # own command, like so:
6
6
  #
7
- # ```ruby
8
- # class MyApp::Command::Hello < Bales::Command
9
- # def self.run(*args, **opts)
10
- # puts "Hello, world!"
11
- # end
12
- # end # produces a `my-app hello` command that prints "Hello, world!"
13
- # ```
7
+ # class MyApp::Command::Hello < Bales::Command
8
+ # def self.run(*args, **opts)
9
+ # puts "Hello, world!"
10
+ # end
11
+ # end # produces a `my-app hello` command that prints "Hello, world!"
14
12
  #
15
13
  # Note that the above will accept any number of arguments (including none
16
14
  # at all!). If you want to change this behavior, change `self.run`'s
17
15
  # signature, like so:
18
16
  #
19
- # ```ruby
20
- # class MyApp::Command::Smack < Bales::Command
21
- # def self.run(target, **opts)
22
- # puts "#{target} has been smacked with a large trout"
17
+ # class MyApp::Command::Smack < Bales::Command
18
+ # def self.run(target, **opts)
19
+ # puts "#{target} has been smacked with a large trout"
20
+ # end
23
21
  # end
24
- # end
25
- # ```
26
22
  #
27
23
  # Subcommands are automatically derived from namespacing, like so:
28
24
  #
29
- # ```ruby
30
- # class MyApp::Command::Foo::Bar < Bales::Command
31
- # def self.run(*args, **opts)
32
- # # ...
33
- # end
34
- # end # produces `my-app foo bar`
35
- # ```
25
+ # class MyApp::Command::Foo::Bar < Bales::Command
26
+ # def self.run(*args, **opts)
27
+ # # ...
28
+ # end
29
+ # end # produces `my-app foo bar`
36
30
  #
37
31
  # Camel-cased command classes can be accessed using either hyphenation or
38
32
  # underscores, like so:
39
33
  #
40
- # ```ruby
41
- # class MyApp::Command::FooBarBaz < Bales::Command
42
- # # ...
43
- # end
44
- # # valid result: "my-app foo-bar-baz"
45
- # # also valid: "my-app foo_bar_baz"
46
- # ```
34
+ # class MyApp::Command::FooBarBaz < Bales::Command
35
+ # # ...
36
+ # end
37
+ # # valid result: "my-app foo-bar-baz"
38
+ # # also valid: "my-app foo_bar_baz"
39
+ #
47
40
  module Bales
48
41
  class Command
42
+ ##
43
+ # Accessor for the options hash generated by +#option+.
49
44
  def self.options
50
45
  @options ||= {}
51
46
  @options
52
47
  end
48
+ ##
49
+ # Setter for the options hash generated by +#option+. Usually not
50
+ # needed, since that's what +#option+ is for.
53
51
  def self.options=(new)
54
52
  @options = new
55
53
  end
@@ -59,13 +57,11 @@ module Bales
59
57
  # block, which should accept an array of arguments and a hash of options.
60
58
  # For example:
61
59
  #
62
- # ```ruby
63
- # class MyApp::Hello < Bales::Command
64
- # action do |args, opts|
65
- # puts "Hello, world!"
60
+ # class MyApp::Hello < Bales::Command
61
+ # action do |args, opts|
62
+ # puts "Hello, world!"
63
+ # end
66
64
  # end
67
- # end
68
- # ```
69
65
  def self.action(&code)
70
66
  @action = code
71
67
  end
@@ -78,41 +74,39 @@ module Bales
78
74
  # Defines a named option that the command will accept, along with some
79
75
  # named arguments:
80
76
  #
81
- # `:short_form` (optional)
82
- # : A shorthand flag to use for the option (like `-v`). This should be a
83
- # string, like `"-v"`.
84
- #
85
- # `:long_form` (optional)
86
- # : A longhand flag to use for the option (like `--verbose`). This is
87
- # derived from the name of the option if not specified. This should be
88
- # a string, like `"--verbose"`
77
+ # [+:short_form+ (optional)] A shorthand flag to use for the option
78
+ # (like +-v+). This should be a string, like
79
+ # +"-v"+.
89
80
  #
90
- # `:type` (optional)
91
- # : The type that this option represents. Defaults to `TrueClass`.
92
- # Should be a valid class name, like `String` or `Integer`
81
+ # [+:long_form+ (optional)] A longhand flag to use for the option (like
82
+ # +--verbose+). This is derived from the name
83
+ # of the option if not specified. This should
84
+ # be a string, like +"--verbose"+
93
85
  #
94
- # A special note on boolean options: if you want your boolean to
95
- # default to `true`, set `:type` to `TrueClass`. Likewise, if you want
96
- # it to default to `false`, set `:type` to `FalseClass`.
86
+ # [+:type+ (optional)] The type that this option represents.
87
+ # Defaults to +TrueClass+. Should be a valid
88
+ # class name, like +String+ or +Integer+
97
89
  #
98
- # `:arg` (optional)
99
- # : The name of the argument this option accepts. This should be a
100
- # symbol (like :level) or `false` (if the option is a boolean flag).
101
- # Defaults to the name of the option or (if the option's `:type` is
102
- # `TrueClass` or `FalseClass`) `false`.
90
+ # A special note on boolean options: if you
91
+ # want your boolean to default to `true`, set
92
+ # +:type+ to +TrueClass+. Likewise, if you
93
+ # want it to default to +false+, set +:type+
94
+ # to +FalseClass+.
103
95
  #
104
- # If this is an array, and `:type` is set to `Enumerable` or some
105
- # subclass thereof, this will instead be interpreted as a list of
106
- # sample arguments during option parsing. It's recommended you set
107
- # this accordingly if `:type` is `Enumerable` or any of its subclasses.
96
+ # [+:arg+ (optional)] The name of the argument this option
97
+ # accepts. This should be a symbol (like
98
+ # :level) or +false+ (if the option is a
99
+ # boolean flag). Defaults to the name of the
100
+ # option or (if the option's +:type+ is
101
+ # +TrueClass+ or +FalseClass+) +false+.
108
102
  #
109
- # `:required` (optional)
110
- # : Whether or not the option is required. This should be a boolean
111
- # (`true` or `false`). Default is `false`.
103
+ # [+:required+ (optional)] Whether or not the option is required. This
104
+ # should be a boolean (+true+ or +false+).
105
+ # Default is `false`.
112
106
  #
113
- # Aside from the hash of option-options, `option` takes a single `name`
107
+ # Aside from the hash of option-options, +option+ takes a single +name+
114
108
  # argument, which should be a symbol representing the name of the option
115
- # to be set, like `:verbose`.
109
+ # to be set, like +:verbose+.
116
110
  def self.option(name, **opts)
117
111
  name = name.to_sym
118
112
  opts[:long_form] ||= "--#{name.to_s}".gsub("_","-")
@@ -138,7 +132,7 @@ module Bales
138
132
  ##
139
133
  # Takes an ARGV-like array and returns a hash of options and what's left
140
134
  # of the original array. This is rarely needed for normal use, but is
141
- # an integral part of how a Bales::Application parses the ARGV it
135
+ # an integral part of how a +Bales::Application+ parses the ARGV it
142
136
  # receives.
143
137
  #
144
138
  # Normally, this should be perfectly fine to leave alone, but if you
data/lib/bales/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bales
2
- VERSION="0.0.1"
2
+ VERSION="0.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bales
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan S. Northrup
@@ -20,7 +20,6 @@ files:
20
20
  - README.md
21
21
  - lib/bales.rb
22
22
  - lib/bales.rb~
23
- - lib/bales/#command.rb#
24
23
  - lib/bales/application.rb
25
24
  - lib/bales/application.rb~
26
25
  - lib/bales/command.rb
@@ -1,196 +0,0 @@
1
- require 'optparse'
2
-
3
- ##
4
- # Base class for all Bales commands. Subclass this class to create your
5
- # own command, like so:
6
- #
7
- # ```ruby
8
- # class MyApp::Command::Hello < Bales::Command
9
- # def self.run(*args, **opts)
10
- # puts "Hello, world!"
11
- # end
12
- # end # produces a `my-app hello` command that prints "Hello, world!"
13
- # ```
14
- #
15
- # Note that the above will accept any number of arguments (including none
16
- # at all!). If you want to change this behavior, change `self.run`'s
17
- # signature, like so:
18
- #
19
- # ```ruby
20
- # class MyApp::Command::Smack < Bales::Command
21
- # def self.run(target, **opts)
22
- # puts "#{target} has been smacked with a large trout"
23
- # end
24
- # end
25
- # ```
26
- #
27
- # Subcommands are automatically derived from namespacing, like so:
28
- #
29
- # ```ruby
30
- # class MyApp::Command::Foo::Bar < Bales::Command
31
- # def self.run(*args, **opts)
32
- # # ...
33
- # end
34
- # end # produces `my-app foo bar`
35
- # ```
36
- #
37
- # Camel-cased command classes can be accessed using either hyphenation or
38
- # underscores, like so:
39
- #
40
- # ```ruby
41
- # class MyApp::Command::FooBarBaz < Bales::Command
42
- # # ...
43
- # end
44
- # # valid result: "my-app foo-bar-baz"
45
- # # also valid: "my-app foo_bar_baz"
46
- # ```
47
- module Bales
48
- class Command
49
- def self.options
50
- @options ||= {}
51
- @options
52
- end
53
- def self.options=(new)
54
- @options = new
55
- end
56
-
57
- ##
58
- # Assigns an action to this command. Said action is represented as a
59
- # block, which should accept an array of arguments and a hash of options.
60
- # For example:
61
- #
62
- # ```ruby
63
- # class MyApp::Hello < Bales::Command
64
- # action do |args, opts|
65
- # puts "Hello, world!"
66
- # end
67
- # end
68
- # ```
69
- def self.action(&code)
70
- @action = code
71
- end
72
-
73
- def self.run(*args, **opts)
74
- @action.call(args, opts) unless @action.nil?
75
- end
76
-
77
- ##
78
- # Defines a named option that the command will accept, along with some
79
- # named arguments:
80
- #
81
- # `:short_form` (optional)
82
- # : A shorthand flag to use for the option (like `-v`). This should be a
83
- # string, like `"-v"`.
84
- #
85
- # `:long_form` (optional)
86
- # : A longhand flag to use for the option (like `--verbose`). This is
87
- # derived from the name of the option if not specified. This should be
88
- # a string, like `"--verbose"`
89
- #
90
- # `:type` (optional)
91
- # : The type that this option represents. Defaults to `TrueClass`.
92
- # Should be a valid class name, like `String` or `Integer`
93
- #
94
- # A special note on boolean options: if you want your boolean to
95
- # default to `true`, set `:type` to `TrueClass`. Likewise, if you want
96
- # it to default to `false`, set `:type` to `FalseClass`.
97
- #
98
- # `:arg` (optional)
99
- # : The name of the argument this option accepts. This should be a
100
- # symbol (like :level) or `false` (if the option is a boolean flag).
101
- # Defaults to the name of the option or (if the option's `:type` is
102
- # `TrueClass` or `FalseClass`) `false`.
103
- #
104
- # If this is an array, and `:type` is set to `Enumerable` or some
105
- # subclass thereof, this will instead be interpreted as a list of
106
- # sample arguments during option parsing. It's recommended you set
107
- # this accordingly if `:type` is `Enumerable` or any of its subclasses.
108
- #
109
- # `:required` (optional)
110
- # : Whether or not the option is required. This should be a boolean
111
- # (`true` or `false`). Default is `false`.
112
- #
113
- # Aside from the hash of option-options, `option` takes a single `name`
114
- # argument, which should be a symbol representing the name of the option
115
- # to be set, like `:verbose`.
116
- def self.option(name, **opts)
117
- name = name.to_sym
118
- opts[:long_form] ||= "--#{name.to_s}".gsub("_","-")
119
-
120
- opts[:type] = String if opts[:type].nil?
121
-
122
- unless opts[:type].is_a? Class
123
- raise ArgumentError, ":type option should be a valid class"
124
- end
125
-
126
- if (opts[:type].ancestors & [TrueClass, FalseClass]).empty?
127
- opts[:arg] ||= name
128
- end
129
-
130
- opts[:default] = false if opts[:type].ancestors.include? TrueClass
131
- opts[:default] = true if opts[:type].ancestors.include? FalseClass
132
-
133
- result = options
134
- result[name] = opts
135
- options = result
136
- end
137
-
138
- ##
139
- # Takes an ARGV-like array and returns a hash of options and what's left
140
- # of the original array. This is rarely needed for normal use, but is
141
- # an integral part of how a Bales::Application parses the ARGV it
142
- # receives.
143
- #
144
- # Normally, this should be perfectly fine to leave alone, but if you
145
- # prefer to define your own parsing method (e.g. if you want to specify
146
- # an alternative format for command-line options, or you are otherwise
147
- # dissatisfied with the default approach of wrapping OptionParser), this
148
- # is the method you'd want to override.
149
- def self.parse_opts(argv)
150
- optparser = OptionParser.new
151
- result = {}
152
- options.each do |name, opts|
153
- result[name] = opts[:default]
154
- parser_args = []
155
- parser_args.push opts[:short_form] if opts[:short_form]
156
- if (opts[:type].ancestors & [TrueClass,FalseClass]).empty?
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
- end
163
- parser_args.push opts[:type]
164
- else
165
- parser_args.push opts[:long_form]
166
- end
167
- parser_args.push opts[:description]
168
-
169
- if opts[:type].ancestors.include? FalseClass
170
- optparser.on(*parser_args) do
171
- result[name] = false
172
- end
173
- elsif opts[:type].ancestors.include? TrueClass
174
- optparser.on(*parser_args) do
175
- result[name] = true
176
- end
177
- else
178
- optparser.on(*parser_args) do |value|
179
- result[name] = value
180
- end
181
- end
182
- end
183
-
184
- optparser.parse! argv
185
- return result, argv
186
- end
187
- end
188
- end
189
-
190
- ##
191
- # Default help command. You'll probably use your own...
192
- class Bales::Command::Help < Bales::Command
193
- action do |args, opts|
194
- puts "This will someday output some help text"
195
- end
196
- end