baretest 0.2.4 → 0.4.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +6 -6
- data/MANIFEST.txt +40 -18
- data/README.rdoc +8 -1
- data/bin/baretest +126 -118
- data/doc/baretest.rdoc +1 -1
- data/doc/mocking_stubbing_test_doubles.rdoc +31 -3
- data/doc/news/news-0.3.0.rdoc +7 -0
- data/doc/quickref.rdoc +74 -28
- data/doc/whats_going_on.rdoc +5 -0
- data/doc/writing_tests.rdoc +25 -13
- data/examples/components/rack-test.rb +17 -0
- data/examples/{tests/irb_mode → irb_mode}/failures.rb +0 -0
- data/examples/rake/test.rake +40 -0
- data/examples/tests/01_basics_I.rb +34 -0
- data/examples/tests/02_basics_II_helpers.rb +25 -0
- data/examples/tests/03_basics_III_setup_and_teardown.rb +53 -0
- data/examples/tests/04_advanced_I_dependencies.rb +31 -0
- data/examples/tests/05_advanced_II_tags.rb +12 -0
- data/examples/tests/06_advanced_III_requires.rb +21 -0
- data/examples/tests/07_advanced_IV_components.rb +48 -0
- data/examples/tests/08_expert_I_setup_variants.rb +46 -0
- data/lib/baretest.rb +142 -21
- data/lib/baretest/assertion.rb +83 -92
- data/lib/baretest/assertion/context.rb +9 -0
- data/lib/baretest/assertion/support.rb +88 -61
- data/lib/baretest/commandline.rb +268 -0
- data/lib/baretest/formatter.rb +58 -0
- data/lib/baretest/invalidselectors.rb +24 -0
- data/lib/baretest/irb_mode.rb +100 -58
- data/lib/baretest/persistence.rb +94 -0
- data/lib/baretest/run.rb +138 -37
- data/lib/baretest/run/cli.rb +97 -43
- data/lib/baretest/run/minimal.rb +2 -1
- data/lib/baretest/run/none.rb +21 -0
- data/lib/baretest/run/xml.rb +21 -19
- data/lib/baretest/setup.rb +2 -0
- data/lib/baretest/status.rb +93 -0
- data/lib/baretest/suite.rb +185 -59
- data/lib/baretest/uid.rb +51 -0
- data/lib/baretest/use/mocha.rb +24 -0
- data/lib/baretest/use/rack_test.rb +9 -0
- data/lib/baretest/use/rr.rb +17 -0
- data/lib/baretest/version.rb +18 -4
- data/lib/command.rb +36 -0
- data/lib/command/argument.rb +11 -0
- data/lib/command/decoratinghash.rb +31 -0
- data/lib/command/definition.rb +294 -0
- data/lib/command/directorynotfounderror.rb +11 -0
- data/lib/command/env.rb +11 -0
- data/lib/command/filenotfounderror.rb +11 -0
- data/lib/command/kernel.rb +14 -0
- data/lib/command/nodirectoryerror.rb +11 -0
- data/lib/command/nofileerror.rb +11 -0
- data/lib/command/option.rb +16 -0
- data/lib/command/parser.rb +145 -0
- data/lib/command/result.rb +11 -0
- data/lib/command/types.rb +33 -0
- data/lib/command/version.rb +28 -0
- data/test/setup.rb +3 -0
- data/test/suite/lib/baretest.rb +0 -178
- data/test/suite/lib/baretest/assertion.rb +133 -112
- data/test/suite/lib/baretest/assertion/context.rb +40 -0
- data/test/suite/lib/baretest/assertion/failure.rb +19 -0
- data/test/suite/lib/baretest/assertion/skip.rb +19 -0
- data/test/suite/lib/baretest/assertion/support.rb +366 -84
- data/test/suite/lib/baretest/run.rb +114 -15
- data/test/suite/lib/baretest/suite.rb +70 -29
- metadata +46 -24
- data/examples/test.rake +0 -65
- data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
- data/examples/tests/mock_developer/test/setup.rb +0 -57
- data/examples/tests/mock_developer/test/suite/mock_demo.rb +0 -19
- data/examples/tests/overview/test.rb +0 -89
- data/examples/tests/variations/variations_01.rb +0 -14
- data/examples/tests/variations/variations_02.rb +0 -19
- data/examples/tests/variations/variations_03.rb +0 -19
- data/lib/baretest/mocha.rb +0 -18
- data/lib/baretest/rr.rb +0 -16
- data/lib/baretest/run/errors.rb +0 -49
- data/lib/baretest/skipped.rb +0 -15
- data/lib/baretest/skipped/assertion.rb +0 -20
- data/lib/baretest/skipped/suite.rb +0 -49
- data/test/external/bootstraptest.rb +0 -5
- data/test/external/bootstrapwrap.rb +0 -2
- data/test/helper/mocks.rb +0 -0
data/lib/baretest/uid.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
|
11
|
+
# Generate a unique ID.
|
12
|
+
# Not using uuid simply to avoid two dependencies (uuid, and uuid's dependency
|
13
|
+
# 'macaddr').
|
14
|
+
class UID
|
15
|
+
|
16
|
+
# :nodoc:
|
17
|
+
Epoch = Time.utc(2000,1,1).to_i
|
18
|
+
|
19
|
+
# The numeric value of the uid (an Integer)
|
20
|
+
attr_reader :value
|
21
|
+
|
22
|
+
# Returns a 32byte long String containing a new 16 byte random value
|
23
|
+
# in hex representation
|
24
|
+
def self.hex_uid
|
25
|
+
new.hex
|
26
|
+
end
|
27
|
+
|
28
|
+
# Create a 128bit (16 Byte) long random number
|
29
|
+
def initialize
|
30
|
+
now = Time.now
|
31
|
+
|
32
|
+
# Works for the next 100 years - should be enough
|
33
|
+
# after that, it'll wrap around.
|
34
|
+
time_part_52 = (((now.to_i-Epoch) & 0xffffffff) << 20) + now.usec
|
35
|
+
|
36
|
+
# Not solid, but for the purposes, should work
|
37
|
+
process_part32 = (Thread.current.object_id ^ Process.pid) & 0xfffffffff
|
38
|
+
|
39
|
+
# Add a bit of random noise
|
40
|
+
random_part44 = Kernel.rand(0x100000000000)
|
41
|
+
|
42
|
+
@value = (random_part44 << 84) + (process_part32 << 52) + time_part_52
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns a 32byte long String containing the 16 byte random value
|
46
|
+
# in hex representation
|
47
|
+
def hex
|
48
|
+
"%032x" % @value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Original by dominikh
|
2
|
+
# Adapted to :use framework by apeiros
|
3
|
+
|
4
|
+
# This file provides integration with the "mocha" mocking framework.
|
5
|
+
|
6
|
+
|
7
|
+
# Load this file and get integration with the "rr" mocking framework.
|
8
|
+
|
9
|
+
BareTest.new_component :mocha do
|
10
|
+
require 'mocha'
|
11
|
+
|
12
|
+
BareTest::Assertion::Context.send :include Mocha::API
|
13
|
+
|
14
|
+
teardown do
|
15
|
+
begin
|
16
|
+
mocha_verify
|
17
|
+
rescue Mocha::ExpectationError => e
|
18
|
+
@reason = e.message
|
19
|
+
@status = :failure
|
20
|
+
ensure
|
21
|
+
mocha_teardown
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Original by Tass`
|
2
|
+
# Adapted to :use framework by apeiros
|
3
|
+
|
4
|
+
BareTest.new_component :rr do
|
5
|
+
require 'rr'
|
6
|
+
|
7
|
+
BareTest::Assertion::Context.send :include, RR::Adapters::RRMethods
|
8
|
+
|
9
|
+
teardown do
|
10
|
+
begin
|
11
|
+
::RR.verify
|
12
|
+
rescue ::RR::Errors => e
|
13
|
+
@reason = e.message
|
14
|
+
@status = :failure
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/baretest/version.rb
CHANGED
@@ -12,17 +12,31 @@ module BareTest
|
|
12
12
|
module VERSION
|
13
13
|
|
14
14
|
# The major version number
|
15
|
-
MAJOR
|
15
|
+
MAJOR = 0
|
16
16
|
|
17
17
|
# The minor version number
|
18
|
-
MINOR
|
18
|
+
MINOR = 4
|
19
19
|
|
20
20
|
# The tiny version number
|
21
|
-
TINY
|
21
|
+
TINY = 0
|
22
|
+
|
23
|
+
# Prerelease number - nil for release versions
|
24
|
+
PRERELEASE = 1
|
25
|
+
|
26
|
+
# The version as a string
|
27
|
+
STRING = %{#{MAJOR}.#{MINOR||0}.#{TINY||0}#{".pre#{PRERELEASE}" if PRERELEASE}}
|
28
|
+
|
29
|
+
# The version as an array
|
30
|
+
ARRAY = [MAJOR || 0, MINOR || 0, TINY || 0, PRERELEASE].compact
|
22
31
|
|
23
32
|
# The version as a string
|
24
33
|
def self.to_s
|
25
|
-
|
34
|
+
STRING
|
35
|
+
end
|
36
|
+
|
37
|
+
# The version as an array
|
38
|
+
def self.to_a
|
39
|
+
ARRAY
|
26
40
|
end
|
27
41
|
end
|
28
42
|
end
|
data/lib/command.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'command/kernel'
|
10
|
+
require 'command/nofileerror'
|
11
|
+
require 'command/nodirectoryerror'
|
12
|
+
require 'command/filenotfounderror'
|
13
|
+
require 'command/directorynotfounderror'
|
14
|
+
require 'command/types'
|
15
|
+
require 'command/argument'
|
16
|
+
require 'command/option'
|
17
|
+
require 'command/env'
|
18
|
+
require 'command/result'
|
19
|
+
require 'command/decoratinghash'
|
20
|
+
require 'command/definition'
|
21
|
+
require 'command/parser'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
module Command
|
26
|
+
def self.define(*args, &block)
|
27
|
+
@main = Definition.new(*args, &block)
|
28
|
+
@main
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.with(argv, &block)
|
32
|
+
parser = Parser.new($command, argv)
|
33
|
+
parser.instance_eval(&block)
|
34
|
+
parser
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009-2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Command
|
10
|
+
class DecoratingHash < Hash
|
11
|
+
attr_accessor :target
|
12
|
+
|
13
|
+
def self.new(target)
|
14
|
+
obj = super() do |h,k| h.target && h.target[k] end
|
15
|
+
obj.target = target
|
16
|
+
obj
|
17
|
+
end
|
18
|
+
|
19
|
+
alias own_size size unless method_defined? :own_size
|
20
|
+
alias own_length own_size
|
21
|
+
|
22
|
+
def size
|
23
|
+
@target ? keys.size : super
|
24
|
+
end
|
25
|
+
alias length size
|
26
|
+
|
27
|
+
def keys
|
28
|
+
@target ? (super | @target.keys) : super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Command
|
10
|
+
class Definition
|
11
|
+
RequiredOptionArgument = /[A-Z][A-Z_]*/
|
12
|
+
OptionArgument = /\[#{RequiredOptionArgument}\]|#{RequiredOptionArgument}/
|
13
|
+
ShortOption = /\A-[A-Za-z](?: #{OptionArgument})?\z/
|
14
|
+
NegationSequence = /\[(?:no-|with-|without-)\]/
|
15
|
+
LongOption = /\A--
|
16
|
+
(?:
|
17
|
+
#{NegationSequence}?[A-Za-z][A-Za-z0-9_-]* |
|
18
|
+
[A-Za-z][A-Za-z0-9_-]*#{NegationSequence}[A-Za-z0-9][A-Za-z0-9_-]
|
19
|
+
)
|
20
|
+
(?:\x20#{OptionArgument})?\z
|
21
|
+
/x
|
22
|
+
|
23
|
+
def self.create_argument(*args)
|
24
|
+
name = Symbol === args.first && args.shift
|
25
|
+
usage = args.shift
|
26
|
+
bare = usage[/\w+/]
|
27
|
+
type = Symbol === args.first && args.shift
|
28
|
+
description = args.shift
|
29
|
+
|
30
|
+
Argument.new(name, bare, usage, type, description)
|
31
|
+
end
|
32
|
+
|
33
|
+
# valid arguments:
|
34
|
+
# name # --> copy from parent
|
35
|
+
# name, short[, long][, type][, description]
|
36
|
+
# name, long[, type][, description]
|
37
|
+
#
|
38
|
+
# short can be
|
39
|
+
# * '-?' (short option without argument)
|
40
|
+
# * '-? REQUIRED' (short option with required argument)
|
41
|
+
# * '-? [OPTIONAL]' (short option with optional
|
42
|
+
# where ? is any of A-Za-z
|
43
|
+
# examples:
|
44
|
+
# * '-a'
|
45
|
+
# * '-a [OPTIONAL_ARG]'
|
46
|
+
# * '-a REQUIRED_ARG'
|
47
|
+
#
|
48
|
+
# long can be
|
49
|
+
# * '--?' (short option without argument)
|
50
|
+
# * '--? REQUIRED' (short option with required argument)
|
51
|
+
# * '--? [OPTIONAL]' (short option with optional
|
52
|
+
# where ? is [A-Za-z0-9][A-Za-z0-9-_]*
|
53
|
+
# It may contain a negation sequence, which is one of '[no-]', '[with-]', '[without-]'
|
54
|
+
# examples:
|
55
|
+
# * '--colored'
|
56
|
+
# * '--[no-]colors'
|
57
|
+
# * '--port PORT'
|
58
|
+
# * '--foo [OPTIONAL_ARG]'
|
59
|
+
#
|
60
|
+
# Only one of short and long may have the argument declared.
|
61
|
+
# Usually you'll have the argument in long and only have it in short if
|
62
|
+
# there's no long at all.
|
63
|
+
#
|
64
|
+
# type can be
|
65
|
+
# * :Virtual
|
66
|
+
# * :Boolean
|
67
|
+
# * :String (default)
|
68
|
+
# * :Integer
|
69
|
+
# * :Float
|
70
|
+
# * :Octal
|
71
|
+
# * :Hex
|
72
|
+
# * :File - requires the provided path to exist and be a file
|
73
|
+
# * :Directory - requires the provided path to exist and be a directory
|
74
|
+
# * :Path
|
75
|
+
#
|
76
|
+
# Exceptions (incomplete):
|
77
|
+
# * ArgumentError with single argument if it doesn't identify an inheritable option
|
78
|
+
# * ArgumentError on invalid short definition
|
79
|
+
# * ArgumentError on invalid long definition
|
80
|
+
# * ArgumentError on option argument declaration in both, short and long definition
|
81
|
+
# * ArgumentError on invalid/unsupported type
|
82
|
+
def self.create_option(name, *args)
|
83
|
+
case args.first when nil, /\A-[^- ]/ then
|
84
|
+
short = args.shift
|
85
|
+
end
|
86
|
+
case args.first when nil, /\A--[^- ]/ then
|
87
|
+
long = args.shift
|
88
|
+
end
|
89
|
+
case args.first when nil, Symbol then
|
90
|
+
type = args.shift
|
91
|
+
end
|
92
|
+
declaration = short ? [short,long].compact.join(", ") : " #{long}"
|
93
|
+
description = args.shift
|
94
|
+
|
95
|
+
raise ArgumentError, "Too many arguments" unless args.empty?
|
96
|
+
raise ArgumentError, "Invalid short declaration: #{short.inspect}" unless (short.nil? || short =~ ShortOption)
|
97
|
+
raise ArgumentError, "Invalid long declaration: #{long.inspect}" unless (long.nil? || long =~ LongOption)
|
98
|
+
raise ArgumentError, "Argument declaration must only be in one of short and long" if (short && long && short =~ /\s/ && long =~ /\s/)
|
99
|
+
|
100
|
+
necessity = :none
|
101
|
+
extract_argument = nil
|
102
|
+
extract_argument = short if short =~ /\s/
|
103
|
+
extract_argument = long if long =~ /\s/
|
104
|
+
if extract_argument then
|
105
|
+
flag, *argument = extract_argument.split(/ /)
|
106
|
+
extract_argument.replace(flag) # long/short should only contain the flag, not the argument declaration as well
|
107
|
+
raise ArgumentError, "Multiple arguments for an option not yet supported" if argument.size > 1
|
108
|
+
if argument.empty?
|
109
|
+
necessity = :none
|
110
|
+
elsif argument.first =~ /\A\[.*\]\z/ then
|
111
|
+
necessity = :optional
|
112
|
+
else
|
113
|
+
necessity = :required
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
negated = nil
|
118
|
+
if long =~ NegationSequence then
|
119
|
+
negated = long.delete('[]')
|
120
|
+
long = long.gsub(NegationSequence, '')
|
121
|
+
end
|
122
|
+
|
123
|
+
Option.new(name, short, long, negated, necessity, type, declaration, description)
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
attr_reader :arguments
|
128
|
+
attr_reader :arguments_by_name
|
129
|
+
attr_reader :default_options
|
130
|
+
attr_reader :options_by_name
|
131
|
+
attr_reader :options_by_flag
|
132
|
+
attr_reader :commands_by_name
|
133
|
+
attr_reader :default_command
|
134
|
+
attr_reader :argument_position
|
135
|
+
attr_reader :env_by_variable
|
136
|
+
attr_reader :parent # parent= must update the DecoratingHashes
|
137
|
+
|
138
|
+
def initialize(parent=nil, default_command=nil, default_options={}, &block)
|
139
|
+
@default_command = default_command
|
140
|
+
@default_options = DecoratingHash.new(@parent && @parent.default_options).update(default_options)
|
141
|
+
@elements = []
|
142
|
+
@parent = parent
|
143
|
+
@arguments_by_name = DecoratingHash.new(@parent && @parent.arguments_by_name)
|
144
|
+
@options_by_name = DecoratingHash.new(@parent && @parent.options_by_name)
|
145
|
+
@options_by_flag = DecoratingHash.new(@parent && @parent.options_by_flag)
|
146
|
+
@commands_by_name = DecoratingHash.new(@parent && @parent.commands_by_name)
|
147
|
+
@env_by_variable = DecoratingHash.new(@parent && @parent.env_by_variable)
|
148
|
+
@argument_position = {}
|
149
|
+
@text = []
|
150
|
+
@placeholders = {}
|
151
|
+
@content_for = [@elements]
|
152
|
+
instance_eval(&block) if block
|
153
|
+
end
|
154
|
+
|
155
|
+
def [](command)
|
156
|
+
command ? @commands_by_name[command] : self
|
157
|
+
end
|
158
|
+
|
159
|
+
def content_for(placeholder)
|
160
|
+
@placeholders[placeholder] ||= []
|
161
|
+
@content_for << @placeholders[placeholder]
|
162
|
+
yield(self)
|
163
|
+
@content_for.pop
|
164
|
+
end
|
165
|
+
|
166
|
+
def usage_text(elements=@elements)
|
167
|
+
longest_arg_bare = elements.grep(Argument).max { |a,b|
|
168
|
+
a.bare.size <=> b.bare.size
|
169
|
+
}
|
170
|
+
longest_option = elements.grep(Option).max { |a,b|
|
171
|
+
a.declaration.size <=> b.declaration.size
|
172
|
+
}
|
173
|
+
longest_env_name = elements.grep(Env).max { |a,b|
|
174
|
+
a.variable.size <=> b.variable.size
|
175
|
+
}
|
176
|
+
longest_arg_bare = longest_arg_bare && longest_arg_bare.bare.size
|
177
|
+
longest_option = longest_option && longest_option.declaration.size
|
178
|
+
longest_env_name = longest_env_name && longest_env_name.variable.size
|
179
|
+
arguments = elements.grep(Argument)
|
180
|
+
|
181
|
+
elements.map { |e|
|
182
|
+
case e
|
183
|
+
when :usage
|
184
|
+
"Usage: #{File.basename($0)} #{arguments.map{|a|a.usage}.join(' ')}\n"
|
185
|
+
when Symbol # placeholder
|
186
|
+
usage_text(@placeholders[e])
|
187
|
+
when Option
|
188
|
+
sprintf " %*s%s\n",
|
189
|
+
-(longest_option+2),
|
190
|
+
e.declaration,
|
191
|
+
e.description
|
192
|
+
when Env
|
193
|
+
sprintf "* %*s%s\n",
|
194
|
+
-longest_env_name-2,
|
195
|
+
e.variable,
|
196
|
+
@options_by_name[e.name].description
|
197
|
+
when String
|
198
|
+
e+"\n"
|
199
|
+
when Argument
|
200
|
+
indent = "\n "+(" "*longest_arg_bare)
|
201
|
+
sprintf " %*s%s\n",
|
202
|
+
-(longest_arg_bare+3),
|
203
|
+
"#{e.bare}:",
|
204
|
+
e.description.to_s.gsub(/\n/, indent)
|
205
|
+
when Definition
|
206
|
+
else
|
207
|
+
"unimplemented(#{e.class})"
|
208
|
+
end
|
209
|
+
}.join('')
|
210
|
+
end
|
211
|
+
|
212
|
+
def usage
|
213
|
+
@content_for.last << :usage
|
214
|
+
end
|
215
|
+
|
216
|
+
def argument(*args)
|
217
|
+
unless @argument_position[args.first]
|
218
|
+
@argument_position[args.first] = @argument_position.size
|
219
|
+
end
|
220
|
+
|
221
|
+
if args.size == 1 then
|
222
|
+
argument = @arguments_by_name[args.first]
|
223
|
+
raise ArgumentError, "No argument with name #{args.first.inspect} in any parent found." unless argument
|
224
|
+
else
|
225
|
+
argument = self.class.create_argument(*args)
|
226
|
+
@arguments_by_name[argument.name] = argument
|
227
|
+
end
|
228
|
+
@content_for.last << argument
|
229
|
+
|
230
|
+
argument
|
231
|
+
end
|
232
|
+
|
233
|
+
def virtual_argument(*args)
|
234
|
+
if args.size == 1 then
|
235
|
+
argument = @arguments_by_name[args.first]
|
236
|
+
raise ArgumentError, "No argument with name #{args.first.inspect} in any parent found." unless argument
|
237
|
+
else
|
238
|
+
argument = self.class.create_argument(*args)
|
239
|
+
@arguments_by_name[argument.name] = argument
|
240
|
+
end
|
241
|
+
|
242
|
+
@content_for.last << argument
|
243
|
+
argument
|
244
|
+
end
|
245
|
+
|
246
|
+
def option(*args)
|
247
|
+
if args.size == 1 then
|
248
|
+
inherited_option = @options_by_name[args.first]
|
249
|
+
raise ArgumentError, "No inherited option #{args.first.inspect}" unless inherited_option
|
250
|
+
@content_for.last << inherited_option
|
251
|
+
|
252
|
+
inherited_option
|
253
|
+
else
|
254
|
+
option = self.class.create_option(*args)
|
255
|
+
|
256
|
+
@options_by_name[option.name] = option
|
257
|
+
@options_by_flag[option.short] = option
|
258
|
+
@options_by_flag[option.long] = option
|
259
|
+
@options_by_flag[option.negated] = option
|
260
|
+
@content_for.last << option
|
261
|
+
|
262
|
+
option
|
263
|
+
end
|
264
|
+
end
|
265
|
+
alias o option
|
266
|
+
|
267
|
+
def text(*args)
|
268
|
+
if args.size == 2 then
|
269
|
+
indent, text = *args
|
270
|
+
text = text.gsub(/^/, indent)
|
271
|
+
else
|
272
|
+
text = args.first
|
273
|
+
end
|
274
|
+
@text << text
|
275
|
+
@content_for.last << text
|
276
|
+
end
|
277
|
+
|
278
|
+
def placeholder(identifier)
|
279
|
+
@content_for.last << identifier
|
280
|
+
end
|
281
|
+
|
282
|
+
def env_option(name, variable)
|
283
|
+
env = Env.new(name, variable)
|
284
|
+
@env_by_variable[variable] = env
|
285
|
+
@content_for.last << env
|
286
|
+
end
|
287
|
+
|
288
|
+
def command(*args, &block)
|
289
|
+
definition = Definition.new(self, *args, &block)
|
290
|
+
@commands_by_name[args.first] = definition
|
291
|
+
@content_for.last << definition
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|