bahuvrihi-tap 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +69 -0
- data/MIT-LICENSE +21 -0
- data/README +119 -0
- data/bin/tap +114 -0
- data/cmd/console.rb +42 -0
- data/cmd/destroy.rb +16 -0
- data/cmd/generate.rb +16 -0
- data/cmd/run.rb +126 -0
- data/doc/Class Reference +362 -0
- data/doc/Command Reference +153 -0
- data/doc/Tutorial +237 -0
- data/lib/tap.rb +32 -0
- data/lib/tap/app.rb +720 -0
- data/lib/tap/constants.rb +8 -0
- data/lib/tap/env.rb +640 -0
- data/lib/tap/file_task.rb +547 -0
- data/lib/tap/generator/base.rb +109 -0
- data/lib/tap/generator/destroy.rb +37 -0
- data/lib/tap/generator/generate.rb +61 -0
- data/lib/tap/generator/generators/command/command_generator.rb +21 -0
- data/lib/tap/generator/generators/command/templates/command.erb +32 -0
- data/lib/tap/generator/generators/config/config_generator.rb +26 -0
- data/lib/tap/generator/generators/config/templates/doc.erb +12 -0
- data/lib/tap/generator/generators/config/templates/nodoc.erb +8 -0
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +27 -0
- data/lib/tap/generator/generators/file_task/templates/file.txt +11 -0
- data/lib/tap/generator/generators/file_task/templates/result.yml +6 -0
- data/lib/tap/generator/generators/file_task/templates/task.erb +33 -0
- data/lib/tap/generator/generators/file_task/templates/test.erb +29 -0
- data/lib/tap/generator/generators/root/root_generator.rb +55 -0
- data/lib/tap/generator/generators/root/templates/Rakefile +86 -0
- data/lib/tap/generator/generators/root/templates/gemspec +27 -0
- data/lib/tap/generator/generators/root/templates/tapfile +8 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +3 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +5 -0
- data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +15 -0
- data/lib/tap/generator/generators/task/task_generator.rb +27 -0
- data/lib/tap/generator/generators/task/templates/task.erb +14 -0
- data/lib/tap/generator/generators/task/templates/test.erb +21 -0
- data/lib/tap/generator/manifest.rb +14 -0
- data/lib/tap/patches/rake/rake_test_loader.rb +8 -0
- data/lib/tap/patches/rake/testtask.rb +55 -0
- data/lib/tap/patches/ruby19/backtrace_filter.rb +51 -0
- data/lib/tap/patches/ruby19/parsedate.rb +16 -0
- data/lib/tap/root.rb +581 -0
- data/lib/tap/support/aggregator.rb +55 -0
- data/lib/tap/support/assignments.rb +172 -0
- data/lib/tap/support/audit.rb +418 -0
- data/lib/tap/support/batchable.rb +47 -0
- data/lib/tap/support/batchable_class.rb +107 -0
- data/lib/tap/support/class_configuration.rb +194 -0
- data/lib/tap/support/command_line.rb +98 -0
- data/lib/tap/support/comment.rb +270 -0
- data/lib/tap/support/configurable.rb +114 -0
- data/lib/tap/support/configurable_class.rb +296 -0
- data/lib/tap/support/configuration.rb +122 -0
- data/lib/tap/support/constant.rb +70 -0
- data/lib/tap/support/constant_utils.rb +127 -0
- data/lib/tap/support/declarations.rb +111 -0
- data/lib/tap/support/executable.rb +111 -0
- data/lib/tap/support/executable_queue.rb +82 -0
- data/lib/tap/support/framework.rb +71 -0
- data/lib/tap/support/framework_class.rb +199 -0
- data/lib/tap/support/instance_configuration.rb +147 -0
- data/lib/tap/support/lazydoc.rb +428 -0
- data/lib/tap/support/manifest.rb +89 -0
- data/lib/tap/support/run_error.rb +39 -0
- data/lib/tap/support/shell_utils.rb +71 -0
- data/lib/tap/support/summary.rb +30 -0
- data/lib/tap/support/tdoc.rb +404 -0
- data/lib/tap/support/tdoc/tdoc_html_generator.rb +38 -0
- data/lib/tap/support/tdoc/tdoc_html_template.rb +42 -0
- data/lib/tap/support/templater.rb +180 -0
- data/lib/tap/support/validation.rb +410 -0
- data/lib/tap/support/versions.rb +97 -0
- data/lib/tap/task.rb +259 -0
- data/lib/tap/tasks/dump.rb +56 -0
- data/lib/tap/tasks/rake.rb +93 -0
- data/lib/tap/test.rb +37 -0
- data/lib/tap/test/env_vars.rb +29 -0
- data/lib/tap/test/file_methods.rb +377 -0
- data/lib/tap/test/script_methods.rb +144 -0
- data/lib/tap/test/subset_methods.rb +420 -0
- data/lib/tap/test/tap_methods.rb +237 -0
- data/lib/tap/workflow.rb +187 -0
- metadata +145 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rdoc/generators/html_generator'
|
2
|
+
|
3
|
+
# Defines a specialized generator so it can be called for using a --fmt option.
|
4
|
+
class TDocHTMLGenerator < Generators::HTMLGenerator # :nodoc:
|
5
|
+
end
|
6
|
+
|
7
|
+
module Generators # :nodoc:
|
8
|
+
const_set(:RubyToken, RDoc::RubyToken)
|
9
|
+
|
10
|
+
class HtmlClass < ContextUser # :nodoc:
|
11
|
+
alias tdoc_original_value_hash value_hash
|
12
|
+
|
13
|
+
def value_hash
|
14
|
+
# split attributes into configurations and regular attributes
|
15
|
+
configurations, attributes = @context.attributes.partition do |attribute|
|
16
|
+
attribute.kind_of?(Tap::Support::TDoc::ConfigAttr)
|
17
|
+
end
|
18
|
+
|
19
|
+
# set the context attributes to JUST the regular
|
20
|
+
# attributes and process as usual.
|
21
|
+
@context.attributes.clear.concat attributes
|
22
|
+
values = tdoc_original_value_hash
|
23
|
+
|
24
|
+
# set the context attributes to the configurations
|
25
|
+
# and echo the regular processing to produce a list
|
26
|
+
# of configurations
|
27
|
+
@context.attributes.clear.concat configurations
|
28
|
+
@context.sections.each_with_index do |section, i|
|
29
|
+
secdata = values["sections"][i]
|
30
|
+
|
31
|
+
al = build_attribute_list(section)
|
32
|
+
secdata["configurations"] = al unless al.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
values
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rdoc/generators/template/html/html'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Add a template for documenting configurations. Do so by inserting in the
|
5
|
+
# template into the content regions used to template html.
|
6
|
+
# (see 'rdoc/generators/html_generator' line 864)
|
7
|
+
#
|
8
|
+
[
|
9
|
+
RDoc::Page::BODY,
|
10
|
+
RDoc::Page::FILE_PAGE,
|
11
|
+
RDoc::Page::METHOD_LIST].each do |content|
|
12
|
+
|
13
|
+
# this substitution method duplicates the attribute template for configurations
|
14
|
+
# (see rdoc\generators\template\html line 523)
|
15
|
+
#
|
16
|
+
#IF:attributes
|
17
|
+
# <div id="attribute-list">
|
18
|
+
# <h3 class="section-bar">Attributes</h3>
|
19
|
+
#
|
20
|
+
# <div class="name-list">
|
21
|
+
# <table>
|
22
|
+
#START:attributes
|
23
|
+
# <tr class="top-aligned-row context-row">
|
24
|
+
# <td class="context-item-name">%name%</td>
|
25
|
+
#IF:rw
|
26
|
+
# <td class="context-item-value"> [%rw%] </td>
|
27
|
+
#ENDIF:rw
|
28
|
+
#IFNOT:rw
|
29
|
+
# <td class="context-item-value"> </td>
|
30
|
+
#ENDIF:rw
|
31
|
+
# <td class="context-item-desc">%a_desc%</td>
|
32
|
+
# </tr>
|
33
|
+
#END:attributes
|
34
|
+
# </table>
|
35
|
+
# </div>
|
36
|
+
# </div>
|
37
|
+
#ENDIF:attributes
|
38
|
+
#
|
39
|
+
content.gsub!(/IF:attributes.*?ENDIF:attributes/m) do |match|
|
40
|
+
match + "\n\n" + match.gsub(/attributes/, 'configurations').gsub(/Attributes/, 'Configurations')
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Tap
|
5
|
+
module Support
|
6
|
+
|
7
|
+
# Templater is a convenience class for creating ERB templates. As
|
8
|
+
# an OpenStruct, attributes can be assigned/unassigned at will to
|
9
|
+
# a Templater. When the template is built, all the method of
|
10
|
+
# Templater (and hence all the assigned attributes) are available
|
11
|
+
# in the template.
|
12
|
+
#
|
13
|
+
# t = Templater.new( "key: <%= value %>")
|
14
|
+
# t.value = "default"
|
15
|
+
# t.build # => "key: default"
|
16
|
+
#
|
17
|
+
# t.value = "another"
|
18
|
+
# t.build # => "key: another"
|
19
|
+
#
|
20
|
+
# Templater includes the Templater::Utils utility methods.
|
21
|
+
#
|
22
|
+
# === ERB Redirection
|
23
|
+
#
|
24
|
+
# Templater hooks into the ERB templating mechanism by providing itself
|
25
|
+
# as the ERB output target (_erbout). ERB concatenates each line of an
|
26
|
+
# ERB template to _erbout, as can be seen when you look at the src code
|
27
|
+
# evaluated by ERB:
|
28
|
+
#
|
29
|
+
# e = ERB.new("<%= 1 + 2 %>")
|
30
|
+
# e.src # => "_erbout = ''; _erbout.concat(( 1 + 2 ).to_s); _erbout"
|
31
|
+
#
|
32
|
+
# By setting itself as _erbout, instances of Templater can redirect the
|
33
|
+
# output to a temporary target which can then be used in string
|
34
|
+
# transformations. For example, redirection allows indentation of
|
35
|
+
# nested content:
|
36
|
+
#
|
37
|
+
# template = %Q{
|
38
|
+
# # Un-nested content
|
39
|
+
# <% redirect do |target| %>
|
40
|
+
# # Nested content
|
41
|
+
# <% module_nest("Nesting::Module") { target } %>
|
42
|
+
# <% end %>
|
43
|
+
# }
|
44
|
+
#
|
45
|
+
# t = Templater.new(template)
|
46
|
+
# t.build
|
47
|
+
# # => %Q{
|
48
|
+
# # # Un-nested content
|
49
|
+
# # module Nesting
|
50
|
+
# # module Module
|
51
|
+
# # # Nested content
|
52
|
+
# #
|
53
|
+
# # end
|
54
|
+
# # end}
|
55
|
+
#
|
56
|
+
class Templater < OpenStruct
|
57
|
+
|
58
|
+
# Utility methods for Templater; mostly string manipulations
|
59
|
+
# useful in creating documentation.
|
60
|
+
module Utils
|
61
|
+
|
62
|
+
# yamlize converts the object to YAML (using to_yaml), omitting
|
63
|
+
# the header and final newline:
|
64
|
+
#
|
65
|
+
# {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
|
66
|
+
# yamlize {'key' => 'value'} # => "key: value"
|
67
|
+
def yamlize(object)
|
68
|
+
object.to_yaml[5...-1]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Nest the return of the block in the nesting lines.
|
72
|
+
#
|
73
|
+
# nest([["\nmodule Some", "end\n"],["module Nested", "end"]]) { "class Const\nend" }
|
74
|
+
# # => %Q{
|
75
|
+
# # module Some
|
76
|
+
# # module Nested
|
77
|
+
# # class Const
|
78
|
+
# # end
|
79
|
+
# # end
|
80
|
+
# # end
|
81
|
+
# # }
|
82
|
+
#
|
83
|
+
def nest(nesting, indent=" ", line_sep="\n")
|
84
|
+
content = yield
|
85
|
+
return content if nesting.empty?
|
86
|
+
|
87
|
+
depth = nesting.length
|
88
|
+
lines = [indent * depth + content.gsub(/#{line_sep}/, line_sep + indent * depth)]
|
89
|
+
|
90
|
+
nesting.reverse_each do |(start_line, end_line)|
|
91
|
+
depth -= 1
|
92
|
+
lines.unshift(indent * depth + start_line)
|
93
|
+
lines << (indent * depth + end_line)
|
94
|
+
end
|
95
|
+
|
96
|
+
lines.join(line_sep)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Nest the return of the block in the nesting module.
|
100
|
+
#
|
101
|
+
# module_nest('Some::Nested') { "class Const\nend" }
|
102
|
+
# # => %Q{
|
103
|
+
# # module Some
|
104
|
+
# # module Nested
|
105
|
+
# # class Const
|
106
|
+
# # end
|
107
|
+
# # end
|
108
|
+
# # end
|
109
|
+
# # }.strip
|
110
|
+
#
|
111
|
+
def module_nest(const_name, indent=" ", line_sep="\n")
|
112
|
+
nesting = const_name.split(/::/).collect do |name|
|
113
|
+
["module #{name}", "end"]
|
114
|
+
end
|
115
|
+
|
116
|
+
nest(nesting, indent, line_sep) { yield }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
include Utils
|
121
|
+
|
122
|
+
# Initialized a new Templater. An ERB or String may be provided as the
|
123
|
+
# template. If a String is provided, it will be used to initialize an
|
124
|
+
# ERB with a trim_mode of "<>".
|
125
|
+
def initialize(template, attributes={})
|
126
|
+
@template = case template
|
127
|
+
when ERB
|
128
|
+
if template.instance_variable_get(:@src).index('_erbout =') != 0
|
129
|
+
raise ArgumentError, "Templater does not work with ERB templates where eoutvar != '_erbout'"
|
130
|
+
end
|
131
|
+
template
|
132
|
+
when String then ERB.new(template, nil, "<>")
|
133
|
+
else raise ArgumentError, "cannot convert #{template.class} into an ERB template"
|
134
|
+
end
|
135
|
+
|
136
|
+
src = @template.instance_variable_get(:@src)
|
137
|
+
@template.instance_variable_set(:@src, "self." + src)
|
138
|
+
|
139
|
+
super(attributes)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns self (not the underlying erbout storage that actually receives
|
143
|
+
# the output lines). In the ERB context, this method directs erb outputs
|
144
|
+
# to Templater#concat and into the redirect mechanism.
|
145
|
+
def _erbout
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
# Sets the underlying erbout storage to input.
|
150
|
+
def _erbout=(input)
|
151
|
+
@_erbout = input
|
152
|
+
end
|
153
|
+
|
154
|
+
# Redirects output of erb to the redirected_erbout string
|
155
|
+
# for the duration of the block. When redirect completes,
|
156
|
+
# the redirected_erbout is concatenated to the main
|
157
|
+
# erbout storage.
|
158
|
+
def redirect # :yields: redirected_erbout
|
159
|
+
current = @_erbout
|
160
|
+
@_erbout = ""
|
161
|
+
result = yield(@_erbout)
|
162
|
+
@_erbout = current
|
163
|
+
concat(result)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Concatenates the specified input to the underlying erbout storage.
|
167
|
+
def concat(input)
|
168
|
+
@_erbout << input
|
169
|
+
end
|
170
|
+
|
171
|
+
# Build the template. All methods of self will be
|
172
|
+
# accessible in the template.
|
173
|
+
def build
|
174
|
+
@template.result(binding)
|
175
|
+
@_erbout
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,410 @@
|
|
1
|
+
module Tap
|
2
|
+
module Support
|
3
|
+
|
4
|
+
# Validation generates blocks for common validations and transformations of
|
5
|
+
# configurations set through Configurable. In general these blocks allow
|
6
|
+
# configurations to be set to objects of a particular class, or to a string
|
7
|
+
# that can be loaded as YAML into such an object.
|
8
|
+
#
|
9
|
+
# integer = Validation.integer
|
10
|
+
# integer.class # => Proc
|
11
|
+
# integer.call(1) # => 1
|
12
|
+
# integer.call('1') # => 1
|
13
|
+
# integer.call(nil) # => ValidationError
|
14
|
+
#
|
15
|
+
#--
|
16
|
+
# Note the unusual syntax for declaring constants that are blocks
|
17
|
+
# defined by lambda... ex:
|
18
|
+
#
|
19
|
+
# block = lambda {}
|
20
|
+
# CONST = block
|
21
|
+
#
|
22
|
+
# This syntax plays well with RDoc, which otherwise gets jacked
|
23
|
+
# when you do it all in one step.
|
24
|
+
#++
|
25
|
+
module Validation
|
26
|
+
|
27
|
+
# Raised when Validation blocks fail.
|
28
|
+
class ValidationError < ArgumentError
|
29
|
+
def initialize(input, validations)
|
30
|
+
super case
|
31
|
+
when validations.empty?
|
32
|
+
"no validations specified"
|
33
|
+
else
|
34
|
+
validation_str = PP.singleline_pp(validations, "")
|
35
|
+
PP.singleline_pp(input, "expected #{validation_str} but was: ")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Raised when yamlization fails.
|
41
|
+
class YamlizationError < ArgumentError
|
42
|
+
def initialize(input, error)
|
43
|
+
super "#{error} ('#{input}')"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module_function
|
48
|
+
|
49
|
+
# Yaml conversion and checker. Valid if any of the validations
|
50
|
+
# match in a case statement. Otherwise raises an error.
|
51
|
+
|
52
|
+
# Returns input if any of the validations match any of the
|
53
|
+
# inputs, as in a case statement. Raises a ValidationError
|
54
|
+
# otherwise. For example:
|
55
|
+
#
|
56
|
+
# validate(10, [Integer, nil])
|
57
|
+
#
|
58
|
+
# Does the same as:
|
59
|
+
#
|
60
|
+
# case 10
|
61
|
+
# when Integer, nil then input
|
62
|
+
# else raise ValidationError.new(...)
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# Note the validations input must be an Array or nil;
|
66
|
+
# validate will raise an ArgumentError otherwise.
|
67
|
+
# All inputs are considered VALID if validations == nil.
|
68
|
+
def validate(input, validations)
|
69
|
+
case validations
|
70
|
+
when Array
|
71
|
+
|
72
|
+
case input
|
73
|
+
when *validations then input
|
74
|
+
else raise ValidationError.new(input, validations)
|
75
|
+
end
|
76
|
+
|
77
|
+
when nil then input
|
78
|
+
else raise ArgumentError.new("validations must be nil, or an array of valid inputs")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Attempts to load the input as YAML. Raises a YamlizationError
|
83
|
+
# for errors.
|
84
|
+
def yamlize(input)
|
85
|
+
begin
|
86
|
+
YAML.load(input)
|
87
|
+
rescue
|
88
|
+
raise YamlizationError.new(input, $!.message)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns a block that calls validate using the block input
|
93
|
+
# and the input validations. Raises an error if no validations
|
94
|
+
# are specified.
|
95
|
+
def check(*validations)
|
96
|
+
raise ArgumentError.new("no validations specified") if validations.empty?
|
97
|
+
lambda {|input| validate(input, validations) }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns a block that loads input strings as YAML, then
|
101
|
+
# calls validate with the result and the input validations.
|
102
|
+
# Non-string inputs are not converted.
|
103
|
+
#
|
104
|
+
# b = yaml(Integer, nil)
|
105
|
+
# b.class # => Proc
|
106
|
+
# b.call(1) # => 1
|
107
|
+
# b.call("1") # => 1
|
108
|
+
# b.call(nil) # => nil
|
109
|
+
# b.call("str") # => ValidationError
|
110
|
+
#
|
111
|
+
# If no validations are specified, the result will be
|
112
|
+
# returned without validation.
|
113
|
+
def yaml(*validations)
|
114
|
+
lambda do |input|
|
115
|
+
res = input.kind_of?(String) ? yamlize(input) : input
|
116
|
+
validations.empty? ? res : validate(res, validations)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns a block loads a String input as YAML then
|
121
|
+
# validates the result is valid using the input
|
122
|
+
# validations. If the input is not a String, the
|
123
|
+
# input is validated directly.
|
124
|
+
def yamlize_and_check(*validations)
|
125
|
+
lambda do |input|
|
126
|
+
input = yamlize(input) if input.kind_of?(String)
|
127
|
+
validate(input, validations)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns a block that checks the input is a string.
|
132
|
+
# Moreover, strings are re-evaluated as string
|
133
|
+
# literals using %Q.
|
134
|
+
#
|
135
|
+
# string.class # => Proc
|
136
|
+
# string.call('str') # => 'str'
|
137
|
+
# string.call('\n') # => "\n"
|
138
|
+
# string.call("\n") # => "\n"
|
139
|
+
# string.call("%s") # => "%s"
|
140
|
+
# string.call(nil) # => ValidationError
|
141
|
+
# string.call(:sym) # => ValidationError
|
142
|
+
#
|
143
|
+
def string(); STRING; end
|
144
|
+
string_validation_block = lambda do |input|
|
145
|
+
input = validate(input, [String])
|
146
|
+
eval %Q{"#{input}"}
|
147
|
+
end
|
148
|
+
STRING = string_validation_block
|
149
|
+
|
150
|
+
# Same as string but allows nil. Note the special
|
151
|
+
# behavior of the nil string '~' -- rather than
|
152
|
+
# being treated as a string, it is processed as nil
|
153
|
+
# to be consistent with the other [class]_or_nil
|
154
|
+
# methods.
|
155
|
+
#
|
156
|
+
# string_or_nil.call('~') # => nil
|
157
|
+
# string_or_nil.call(nil) # => nil
|
158
|
+
def string_or_nil(); STRING_OR_NIL; end
|
159
|
+
string_or_nil_validation_block = lambda do |input|
|
160
|
+
input = validate(input, [String, nil])
|
161
|
+
case input
|
162
|
+
when nil, '~' then nil
|
163
|
+
else eval %Q{"#{input}"}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
STRING_OR_NIL = string_or_nil_validation_block
|
167
|
+
|
168
|
+
# Returns a block that checks the input is a symbol.
|
169
|
+
# String inputs are loaded as yaml first.
|
170
|
+
#
|
171
|
+
# symbol.class # => Proc
|
172
|
+
# symbol.call(:sym) # => :sym
|
173
|
+
# symbol.call(':sym') # => :sym
|
174
|
+
# symbol.call(nil) # => ValidationError
|
175
|
+
# symbol.call('str') # => ValidationError
|
176
|
+
#
|
177
|
+
def symbol(); SYMBOL; end
|
178
|
+
SYMBOL = yamlize_and_check(Symbol)
|
179
|
+
|
180
|
+
# Same as symbol but allows nil:
|
181
|
+
#
|
182
|
+
# symbol_or_nil.call('~') # => nil
|
183
|
+
# symbol_or_nil.call(nil) # => nil
|
184
|
+
def symbol_or_nil(); SYMBOL_OR_NIL; end
|
185
|
+
SYMBOL_OR_NIL = yamlize_and_check(Symbol, nil)
|
186
|
+
|
187
|
+
# Returns a block that checks the input is true, false or nil.
|
188
|
+
# String inputs are loaded as yaml first.
|
189
|
+
#
|
190
|
+
# boolean.class # => Proc
|
191
|
+
# boolean.call(true) # => true
|
192
|
+
# boolean.call(false) # => false
|
193
|
+
# boolean.call(nil) # => nil
|
194
|
+
#
|
195
|
+
# boolean.call('true') # => true
|
196
|
+
# boolean.call('yes') # => true
|
197
|
+
# boolean.call('FALSE') # => false
|
198
|
+
#
|
199
|
+
# boolean.call(1) # => ValidationError
|
200
|
+
# boolean.call("str") # => ValidationError
|
201
|
+
#
|
202
|
+
def boolean(); BOOLEAN; end
|
203
|
+
BOOLEAN = yamlize_and_check(true, false, nil)
|
204
|
+
|
205
|
+
def switch(); SWITCH; end
|
206
|
+
SWITCH = yamlize_and_check(true, false, nil)
|
207
|
+
|
208
|
+
def flag(); FLAG; end
|
209
|
+
FLAG = yamlize_and_check(true, false, nil)
|
210
|
+
|
211
|
+
# Returns a block that checks the input is an array.
|
212
|
+
# String inputs are loaded as yaml first.
|
213
|
+
#
|
214
|
+
# array.class # => Proc
|
215
|
+
# array.call([1,2,3]) # => [1,2,3]
|
216
|
+
# array.call('[1, 2, 3]') # => [1,2,3]
|
217
|
+
# array.call(nil) # => ValidationError
|
218
|
+
# array.call('str') # => ValidationError
|
219
|
+
#
|
220
|
+
def array(); ARRAY; end
|
221
|
+
ARRAY = yamlize_and_check(Array)
|
222
|
+
|
223
|
+
# Same as array but allows nil:
|
224
|
+
#
|
225
|
+
# array_or_nil.call('~') # => nil
|
226
|
+
# array_or_nil.call(nil) # => nil
|
227
|
+
def array_or_nil(); ARRAY_OR_NIL; end
|
228
|
+
ARRAY_OR_NIL = yamlize_and_check(Array, nil)
|
229
|
+
|
230
|
+
def list(); LIST; end
|
231
|
+
list_block = lambda do |input|
|
232
|
+
if input.kind_of?(String)
|
233
|
+
input = case processed_input = yamlize(input)
|
234
|
+
when Array then processed_input
|
235
|
+
else input.split(/,/).collect {|arg| yamlize(arg) }
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
validate(input, [Array])
|
240
|
+
end
|
241
|
+
LIST = list_block
|
242
|
+
|
243
|
+
# Returns a block that checks the input is a hash.
|
244
|
+
# String inputs are loaded as yaml first.
|
245
|
+
#
|
246
|
+
# hash.class # => Proc
|
247
|
+
# hash.call({'key' => 'value'}) # => {'key' => 'value'}
|
248
|
+
# hash.call('key: value') # => {'key' => 'value'}
|
249
|
+
# hash.call(nil) # => ValidationError
|
250
|
+
# hash.call('str') # => ValidationError
|
251
|
+
#
|
252
|
+
def hash(); HASH; end
|
253
|
+
HASH = yamlize_and_check(Hash)
|
254
|
+
|
255
|
+
# Same as hash but allows nil:
|
256
|
+
#
|
257
|
+
# hash_or_nil.call('~') # => nil
|
258
|
+
# hash_or_nil.call(nil) # => nil
|
259
|
+
def hash_or_nil(); HASH_OR_NIL; end
|
260
|
+
HASH_OR_NIL = yamlize_and_check(Hash, nil)
|
261
|
+
|
262
|
+
# Returns a block that checks the input is an integer.
|
263
|
+
# String inputs are loaded as yaml first.
|
264
|
+
#
|
265
|
+
# integer.class # => Proc
|
266
|
+
# integer.call(1) # => 1
|
267
|
+
# integer.call('1') # => 1
|
268
|
+
# integer.call(1.1) # => ValidationError
|
269
|
+
# integer.call(nil) # => ValidationError
|
270
|
+
# integer.call('str') # => ValidationError
|
271
|
+
#
|
272
|
+
def integer(); INTEGER; end
|
273
|
+
INTEGER = yamlize_and_check(Integer)
|
274
|
+
|
275
|
+
# Same as integer but allows nil:
|
276
|
+
#
|
277
|
+
# integer_or_nil.call('~') # => nil
|
278
|
+
# integer_or_nil.call(nil) # => nil
|
279
|
+
def integer_or_nil(); INTEGER_OR_NIL; end
|
280
|
+
INTEGER_OR_NIL = yamlize_and_check(Integer, nil)
|
281
|
+
|
282
|
+
# Returns a block that checks the input is a float.
|
283
|
+
# String inputs are loaded as yaml first.
|
284
|
+
#
|
285
|
+
# float.class # => Proc
|
286
|
+
# float.call(1.1) # => 1.1
|
287
|
+
# float.call('1.1') # => 1.1
|
288
|
+
# float.call('1.0e+6') # => 1e6
|
289
|
+
# float.call(1) # => ValidationError
|
290
|
+
# float.call(nil) # => ValidationError
|
291
|
+
# float.call('str') # => ValidationError
|
292
|
+
#
|
293
|
+
def float(); FLOAT; end
|
294
|
+
FLOAT = yamlize_and_check(Float)
|
295
|
+
|
296
|
+
# Same as float but allows nil:
|
297
|
+
#
|
298
|
+
# float_or_nil.call('~') # => nil
|
299
|
+
# float_or_nil.call(nil) # => nil
|
300
|
+
def float_or_nil(); FLOAT_OR_NIL; end
|
301
|
+
FLOAT_OR_NIL = yamlize_and_check(Float, nil)
|
302
|
+
|
303
|
+
# Returns a block that checks the input is a number.
|
304
|
+
# String inputs are loaded as yaml first.
|
305
|
+
#
|
306
|
+
# num.class # => Proc
|
307
|
+
# num.call(1.1) # => 1.1
|
308
|
+
# num.call(1) # => 1
|
309
|
+
# num.call(1e6) # => 1e6
|
310
|
+
# num.call('1.1') # => 1.1
|
311
|
+
# num.call('1.0e+6') # => 1e6
|
312
|
+
# num.call(nil) # => ValidationError
|
313
|
+
# num.call('str') # => ValidationError
|
314
|
+
#
|
315
|
+
def num(); NUMERIC; end
|
316
|
+
NUMERIC = yamlize_and_check(Numeric)
|
317
|
+
|
318
|
+
# Same as num but allows nil:
|
319
|
+
#
|
320
|
+
# num_or_nil.call('~') # => nil
|
321
|
+
# num_or_nil.call(nil) # => nil
|
322
|
+
def num_or_nil(); NUMERIC_OR_NIL; end
|
323
|
+
NUMERIC_OR_NIL = yamlize_and_check(Numeric, nil)
|
324
|
+
|
325
|
+
# Returns a block that checks the input is a regexp.
|
326
|
+
# String inputs are converted to regexps using
|
327
|
+
# Regexp#new.
|
328
|
+
#
|
329
|
+
# regexp.class # => Proc
|
330
|
+
# regexp.call(/regexp/) # => /regexp/
|
331
|
+
# regexp.call('regexp') # => /regexp/
|
332
|
+
#
|
333
|
+
# # use of ruby-specific flags can turn on/off
|
334
|
+
# # features like case insensitive matching
|
335
|
+
# regexp.call('(?i)regexp') # => /(?i)regexp/
|
336
|
+
#
|
337
|
+
def regexp(); REGEXP; end
|
338
|
+
regexp_block = lambda do |input|
|
339
|
+
input = Regexp.new(input) if input.kind_of?(String)
|
340
|
+
validate(input, [Regexp])
|
341
|
+
end
|
342
|
+
REGEXP = regexp_block
|
343
|
+
|
344
|
+
# Same as regexp but allows nil. Note the special
|
345
|
+
# behavior of the nil string '~' -- rather than
|
346
|
+
# being converted to a regexp, it is processed as
|
347
|
+
# nil to be consistent with the other [class]_or_nil
|
348
|
+
# methods.
|
349
|
+
#
|
350
|
+
# regexp_or_nil.call('~') # => nil
|
351
|
+
# regexp_or_nil.call(nil) # => nil
|
352
|
+
def regexp_or_nil(); REGEXP_OR_NIL; end
|
353
|
+
regexp_or_nil_block = lambda do |input|
|
354
|
+
input = case input
|
355
|
+
when nil, '~' then nil
|
356
|
+
when String then Regexp.new(input)
|
357
|
+
else input
|
358
|
+
end
|
359
|
+
|
360
|
+
validate(input, [Regexp, nil])
|
361
|
+
end
|
362
|
+
REGEXP_OR_NIL = regexp_or_nil_block
|
363
|
+
|
364
|
+
# Returns a block that checks the input is a range.
|
365
|
+
# String inputs are split into a beginning and
|
366
|
+
# end if possible, where each part is loaded as
|
367
|
+
# yaml before being used to construct a Range.a
|
368
|
+
#
|
369
|
+
# range.class # => Proc
|
370
|
+
# range.call(1..10) # => 1..10
|
371
|
+
# range.call('1..10') # => 1..10
|
372
|
+
# range.call('a..z') # => 'a'..'z'
|
373
|
+
# range.call('-10...10') # => -10...10
|
374
|
+
# range.call(nil) # => ValidationError
|
375
|
+
# range.call('1.10') # => ValidationError
|
376
|
+
# range.call('a....z') # => ValidationError
|
377
|
+
#
|
378
|
+
def range(); RANGE; end
|
379
|
+
range_block = lambda do |input|
|
380
|
+
if input.kind_of?(String) && input =~ /^([^.]+)(\.{2,3})([^.]+)$/
|
381
|
+
input = Range.new(yamlize($1), yamlize($3), $2.length == 3)
|
382
|
+
end
|
383
|
+
validate(input, [Range])
|
384
|
+
end
|
385
|
+
RANGE = range_block
|
386
|
+
|
387
|
+
# Same as range but allows nil:
|
388
|
+
#
|
389
|
+
# range_or_nil.call('~') # => nil
|
390
|
+
# range_or_nil.call(nil) # => nil
|
391
|
+
def range_or_nil(); RANGE_OR_NIL; end
|
392
|
+
range_or_nil_block = lambda do |input|
|
393
|
+
input = case input
|
394
|
+
when nil, '~' then nil
|
395
|
+
when String
|
396
|
+
if input =~ /^([^.]+)(\.{2,3})([^.]+)$/
|
397
|
+
Range.new(yamlize($1), yamlize($3), $2.length == 3)
|
398
|
+
else
|
399
|
+
input
|
400
|
+
end
|
401
|
+
else input
|
402
|
+
end
|
403
|
+
|
404
|
+
validate(input, [Range, nil])
|
405
|
+
end
|
406
|
+
RANGE_OR_NIL = range_or_nil_block
|
407
|
+
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|