bales 0.0.1 → 0.0.2

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