amp-front 0.1.0
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.
- data/.document +5 -0
- data/.gitignore +24 -0
- data/Ampfile +3 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +36 -0
- data/LICENSE +20 -0
- data/README.md +50 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/design_docs/commands.md +91 -0
- data/design_docs/dependencies.md +35 -0
- data/design_docs/plugins.md +47 -0
- data/features/amp.feature +8 -0
- data/features/amp_help.feature +36 -0
- data/features/amp_plugin_list.feature +10 -0
- data/features/step_definitions/amp-front_steps.rb +23 -0
- data/features/support/env.rb +4 -0
- data/lib/amp-front.rb +30 -0
- data/lib/amp-front/dispatch/commands/base.rb +158 -0
- data/lib/amp-front/dispatch/commands/builtin/help.rb +23 -0
- data/lib/amp-front/dispatch/commands/builtin/plugin.rb +24 -0
- data/lib/amp-front/dispatch/commands/validations.rb +171 -0
- data/lib/amp-front/dispatch/runner.rb +86 -0
- data/lib/amp-front/help/entries/__default__.erb +31 -0
- data/lib/amp-front/help/entries/ampfiles.md +42 -0
- data/lib/amp-front/help/entries/commands.erb +6 -0
- data/lib/amp-front/help/entries/new-commands.md +81 -0
- data/lib/amp-front/help/help.rb +312 -0
- data/lib/amp-front/plugins/base.rb +87 -0
- data/lib/amp-front/support/module_extensions.rb +92 -0
- data/lib/amp-front/third_party/maruku.rb +136 -0
- data/lib/amp-front/third_party/maruku/attributes.rb +227 -0
- data/lib/amp-front/third_party/maruku/defaults.rb +71 -0
- data/lib/amp-front/third_party/maruku/errors_management.rb +92 -0
- data/lib/amp-front/third_party/maruku/helpers.rb +260 -0
- data/lib/amp-front/third_party/maruku/input/charsource.rb +326 -0
- data/lib/amp-front/third_party/maruku/input/extensions.rb +69 -0
- data/lib/amp-front/third_party/maruku/input/html_helper.rb +189 -0
- data/lib/amp-front/third_party/maruku/input/linesource.rb +111 -0
- data/lib/amp-front/third_party/maruku/input/parse_block.rb +615 -0
- data/lib/amp-front/third_party/maruku/input/parse_doc.rb +234 -0
- data/lib/amp-front/third_party/maruku/input/parse_span_better.rb +746 -0
- data/lib/amp-front/third_party/maruku/input/rubypants.rb +225 -0
- data/lib/amp-front/third_party/maruku/input/type_detection.rb +147 -0
- data/lib/amp-front/third_party/maruku/input_textile2/t2_parser.rb +163 -0
- data/lib/amp-front/third_party/maruku/maruku.rb +33 -0
- data/lib/amp-front/third_party/maruku/output/to_ansi.rb +223 -0
- data/lib/amp-front/third_party/maruku/output/to_html.rb +991 -0
- data/lib/amp-front/third_party/maruku/output/to_markdown.rb +164 -0
- data/lib/amp-front/third_party/maruku/output/to_s.rb +56 -0
- data/lib/amp-front/third_party/maruku/string_utils.rb +191 -0
- data/lib/amp-front/third_party/maruku/structures.rb +167 -0
- data/lib/amp-front/third_party/maruku/structures_inspect.rb +87 -0
- data/lib/amp-front/third_party/maruku/structures_iterators.rb +61 -0
- data/lib/amp-front/third_party/maruku/textile2.rb +1 -0
- data/lib/amp-front/third_party/maruku/toc.rb +199 -0
- data/lib/amp-front/third_party/maruku/usage/example1.rb +33 -0
- data/lib/amp-front/third_party/maruku/version.rb +40 -0
- data/lib/amp-front/third_party/trollop.rb +766 -0
- data/spec/amp-front_spec.rb +25 -0
- data/spec/command_specs/base_spec.rb +123 -0
- data/spec/command_specs/command_spec.rb +97 -0
- data/spec/command_specs/help_spec.rb +33 -0
- data/spec/command_specs/spec_helper.rb +37 -0
- data/spec/command_specs/validations_spec.rb +267 -0
- data/spec/dispatch_specs/runner_spec.rb +116 -0
- data/spec/dispatch_specs/spec_helper.rb +15 -0
- data/spec/help_specs/help_entry_spec.rb +78 -0
- data/spec/help_specs/help_registry_spec.rb +77 -0
- data/spec/help_specs/spec_helper.rb +15 -0
- data/spec/plugin_specs/base_spec.rb +36 -0
- data/spec/plugin_specs/spec_helper.rb +15 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support_specs/module_extensions_spec.rb +104 -0
- data/spec/support_specs/spec_helper.rb +15 -0
- data/test/third_party_tests/test_trollop.rb +1181 -0
- metadata +192 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Feature: Plugin List Command
|
|
2
|
+
In order to check my plugins
|
|
3
|
+
A user can use the "plugin list" command
|
|
4
|
+
to inspect the Amp runtime environment
|
|
5
|
+
|
|
6
|
+
Scenario: Running plugin list with no parameters
|
|
7
|
+
Given the argument plugin
|
|
8
|
+
And the argument list
|
|
9
|
+
When I run dispatch
|
|
10
|
+
Then I should see "Amp::Plugins::Base"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Given /the argument (.*)/ do |arg|
|
|
2
|
+
@arguments ||= []
|
|
3
|
+
@arguments << arg
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
When /I run dispatch/ do
|
|
7
|
+
dispatch = Amp::Dispatch::Runner.new(@arguments || [])
|
|
8
|
+
@result = swizzling_stdout { dispatch.run! }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Then /I should see "(.*)"/ do |arg|
|
|
12
|
+
@result.should =~ /#{arg}/
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def swizzling_stdout
|
|
16
|
+
new_stdout = StringIO.new
|
|
17
|
+
$stdout, old_stdout = new_stdout, $stdout
|
|
18
|
+
yield
|
|
19
|
+
new_stdout.string
|
|
20
|
+
ensure
|
|
21
|
+
$stdout = old_stdout
|
|
22
|
+
new_stdout.string
|
|
23
|
+
end
|
data/lib/amp-front.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
VERSION = '0.0.1'
|
|
3
|
+
VERSION_TITLE = 'Koyaanisqatsi'
|
|
4
|
+
|
|
5
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
|
6
|
+
|
|
7
|
+
module Dispatch
|
|
8
|
+
autoload :Runner, 'amp-front/dispatch/runner.rb'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Help
|
|
12
|
+
autoload :HelpUI, 'amp-front/help/help.rb'
|
|
13
|
+
autoload :HelpEntry, 'amp-front/help/help.rb'
|
|
14
|
+
autoload :HelpRegistry, 'amp-front/help/help.rb'
|
|
15
|
+
autoload :CommandHelpEntry, 'amp-front/help/help.rb'
|
|
16
|
+
autoload :FileHelpEntry, 'amp-front/help/help.rb'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module Plugins
|
|
20
|
+
autoload :Base, 'amp-front/plugins/base.rb'
|
|
21
|
+
autoload :Registry, 'amp-front/plugins/registry.rb'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
autoload :Command, 'amp-front/dispatch/commands/base.rb'
|
|
25
|
+
autoload :ModuleExtensions, 'amp-front/support/module_extensions.rb'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
autoload :ERB, 'erb'
|
|
29
|
+
autoload :Maruku, 'amp-front/third_party/maruku.rb'
|
|
30
|
+
autoload :Trollop, 'amp-front/third_party/trollop.rb'
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
##################################################################
|
|
2
|
+
# Licensing Information #
|
|
3
|
+
# #
|
|
4
|
+
# The following code is licensed, as standalone code, under #
|
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
|
6
|
+
# #
|
|
7
|
+
# For information on the license of this code when distributed #
|
|
8
|
+
# with and used in conjunction with the other modules in the #
|
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
|
10
|
+
# #
|
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
|
12
|
+
# #
|
|
13
|
+
##################################################################
|
|
14
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'validations.rb'))
|
|
15
|
+
|
|
16
|
+
module Amp
|
|
17
|
+
module Command
|
|
18
|
+
# Creates a new command class and sets its name appropriately. Yields
|
|
19
|
+
# it, so it can be customized by the caller, adding options, an on_call
|
|
20
|
+
# block, and so on.
|
|
21
|
+
def self.create(name)
|
|
22
|
+
@current_base_module ||= Amp::Command
|
|
23
|
+
name = name.capitalize
|
|
24
|
+
new_class = Class.new(Base)
|
|
25
|
+
new_class.name = name
|
|
26
|
+
yield new_class
|
|
27
|
+
@current_base_module.const_set(name, new_class)
|
|
28
|
+
Amp::Help::CommandHelpEntry.new(name.downcase, new_class)
|
|
29
|
+
new_class
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Runs the provided block with a base module of the given name. So
|
|
33
|
+
# instead of creating Amp::Command::NewCommand, this allows you to
|
|
34
|
+
# namespace created code as Amp::Command::MyModule::NewCommand, isolating
|
|
35
|
+
# it from other plugins.
|
|
36
|
+
def self.namespace(namespace)
|
|
37
|
+
old_namespace = @current_base_module ||= Amp::Command
|
|
38
|
+
namespace = namespace.capitalize
|
|
39
|
+
|
|
40
|
+
unless old_namespace.const_defined?(namespace)
|
|
41
|
+
new_namespace = Module.new
|
|
42
|
+
old_namespace.const_set(namespace, new_namespace)
|
|
43
|
+
end
|
|
44
|
+
@current_base_module = const_get(namespace)
|
|
45
|
+
yield
|
|
46
|
+
ensure
|
|
47
|
+
@current_base_module = old_namespace
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# See if the specified module list matches a defined constant
|
|
51
|
+
def self.lookup_const(modules)
|
|
52
|
+
current = Amp::Command
|
|
53
|
+
modules.each do |module_name|
|
|
54
|
+
if module_name =~ /^[A-Za-z0-9_]+$/ && current.const_defined?(module_name)
|
|
55
|
+
current = current.const_get(module_name)
|
|
56
|
+
else
|
|
57
|
+
return current
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
return current
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# return the argument if 'new' would succeed
|
|
64
|
+
def self.creatable(command)
|
|
65
|
+
command.is_a?(Class) ? command : nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Looks up the command with the given name.
|
|
69
|
+
def self.for_name(name)
|
|
70
|
+
modules = name.split.map {|name| name.capitalize}
|
|
71
|
+
creatable(lookup_const(modules))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The base class frmo which all comamnds inherit.
|
|
75
|
+
class Base
|
|
76
|
+
include Validations
|
|
77
|
+
|
|
78
|
+
class << self
|
|
79
|
+
attr_accessor :name, :options, :desc
|
|
80
|
+
end
|
|
81
|
+
self.name = 'Base'
|
|
82
|
+
|
|
83
|
+
# These are the runtime options selected when the command is called.
|
|
84
|
+
attr_accessor :options, :arguments
|
|
85
|
+
|
|
86
|
+
# This tracks all subclasses (and subclasses of subclasses, etc). Plus, this
|
|
87
|
+
# method is inherited, so Wool::Plugins::Git.all_subclasses will have all
|
|
88
|
+
# subclasses of Wool::Plugins::Git!
|
|
89
|
+
def self.all_commands
|
|
90
|
+
@all_commands ||= [self]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# When a Plugin subclass is subclassed, store the subclass and inform the
|
|
94
|
+
# next superclass up the inheritance hierarchy.
|
|
95
|
+
def self.inherited(klass)
|
|
96
|
+
klass.name ||= 'anonymous ' + self.name
|
|
97
|
+
self.all_commands << klass
|
|
98
|
+
next_klass = self.superclass
|
|
99
|
+
while next_klass != Amp::Command::Base.superclass
|
|
100
|
+
next_klass.send(:inherited, klass)
|
|
101
|
+
next_klass = next_klass.superclass
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Specifies the block to run, or returns the block.
|
|
106
|
+
def self.on_call(&block)
|
|
107
|
+
@on_call = block if block_given?
|
|
108
|
+
@on_call
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.desc(*args)
|
|
112
|
+
self.desc = args[0] if args.size == 1 && args[0].is_a?(String)
|
|
113
|
+
@desc ||= ""
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.options
|
|
117
|
+
@options ||= []
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.opt(*args)
|
|
121
|
+
self.options << args
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Runs the command with the provided options and arguments.
|
|
125
|
+
def call(options, arguments)
|
|
126
|
+
self.options = options
|
|
127
|
+
self.arguments = arguments
|
|
128
|
+
instance_eval(&self.class.on_call)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Collects the options specific to this command and returns them.
|
|
132
|
+
def collect_options(arguments)
|
|
133
|
+
args = arguments.dup
|
|
134
|
+
base_options = self.class.options # Trollop::options uses instance_eval
|
|
135
|
+
@parser, hash = Trollop::options(args) do
|
|
136
|
+
base_options.each do |option|
|
|
137
|
+
opt *option
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
[hash, args]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def education
|
|
144
|
+
if @parser
|
|
145
|
+
output = StringIO.new
|
|
146
|
+
@parser.educate(output)
|
|
147
|
+
output.string
|
|
148
|
+
else
|
|
149
|
+
''
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
Dir[File.expand_path(File.dirname(__FILE__)) + '/builtin/**/*.rb'].each do |file|
|
|
157
|
+
require file
|
|
158
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
##################################################################
|
|
2
|
+
# Licensing Information #
|
|
3
|
+
# #
|
|
4
|
+
# The following code is licensed, as standalone code, under #
|
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
|
6
|
+
# #
|
|
7
|
+
# For information on the license of this code when distributed #
|
|
8
|
+
# with and used in conjunction with the other modules in the #
|
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
|
10
|
+
# #
|
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
|
12
|
+
# #
|
|
13
|
+
##################################################################
|
|
14
|
+
Amp::Command.create('help') do |c|
|
|
15
|
+
c.desc "Prints the help for the program."
|
|
16
|
+
|
|
17
|
+
c.on_call do
|
|
18
|
+
output = ""
|
|
19
|
+
|
|
20
|
+
cmd_name = arguments.empty? ? "__default__" : arguments.first
|
|
21
|
+
Amp::Help::HelpUI.print_entry(cmd_name, options)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
##################################################################
|
|
2
|
+
# Licensing Information #
|
|
3
|
+
# #
|
|
4
|
+
# The following code is licensed, as standalone code, under #
|
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
|
6
|
+
# #
|
|
7
|
+
# For information on the license of this code when distributed #
|
|
8
|
+
# with and used in conjunction with the other modules in the #
|
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
|
10
|
+
# #
|
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
|
12
|
+
# #
|
|
13
|
+
##################################################################
|
|
14
|
+
Amp::Command.namespace 'plugin' do
|
|
15
|
+
Amp::Command.create('list') do |c|
|
|
16
|
+
c.desc "Lists all the plugins known to Amp."
|
|
17
|
+
|
|
18
|
+
c.on_call do
|
|
19
|
+
Amp::Plugins::Base.all_plugins.each do |plugin|
|
|
20
|
+
puts plugin.name
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
##################################################################
|
|
2
|
+
# Licensing Information #
|
|
3
|
+
# #
|
|
4
|
+
# The following code is licensed, as standalone code, under #
|
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
|
6
|
+
# #
|
|
7
|
+
# For information on the license of this code when distributed #
|
|
8
|
+
# with and used in conjunction with the other modules in the #
|
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
|
10
|
+
# #
|
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
|
12
|
+
# #
|
|
13
|
+
##################################################################
|
|
14
|
+
|
|
15
|
+
module Amp
|
|
16
|
+
module Command
|
|
17
|
+
module Validations
|
|
18
|
+
def self.included(base)
|
|
19
|
+
base.extend(ClassMethods)
|
|
20
|
+
end
|
|
21
|
+
module ClassMethods
|
|
22
|
+
def before_blocks
|
|
23
|
+
@before_blocks ||= []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def after_blocks
|
|
27
|
+
@after_blocks ||= []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Specifies one or more "before" callbacks that are run before
|
|
31
|
+
# the command executes. If any of them return non-truthy, then
|
|
32
|
+
# execution halts.
|
|
33
|
+
#
|
|
34
|
+
# @param block [Proc] a block to run
|
|
35
|
+
def before(&block)
|
|
36
|
+
before_blocks << block
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Specifies one or more "after" callbacks that are run before
|
|
40
|
+
# the command executes. If any of them return non-truthy, then
|
|
41
|
+
# execution halts.
|
|
42
|
+
#
|
|
43
|
+
# @param block [Proc] a block to run
|
|
44
|
+
def after(&block)
|
|
45
|
+
after_blocks << block
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Validates that the given block runs and returns true.
|
|
49
|
+
# TODO(adgar): Document how :if, :unless work
|
|
50
|
+
def validates_block(options={}, &block)
|
|
51
|
+
before do |opts, args|
|
|
52
|
+
if options[:if] || options[:unless]
|
|
53
|
+
checker = options[:if] || options[:unless]
|
|
54
|
+
result = if checker.is_a?(Proc)
|
|
55
|
+
checker.call(opts, args)
|
|
56
|
+
else
|
|
57
|
+
new.send(checker, opts, args)
|
|
58
|
+
end
|
|
59
|
+
result = !result if options[:unless]
|
|
60
|
+
next true unless result
|
|
61
|
+
end
|
|
62
|
+
block.call(opts, args)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Validates each the given options by running their values through the
|
|
67
|
+
# block.
|
|
68
|
+
def validates_each(*syms, &block)
|
|
69
|
+
options = syms.last.is_a?(Hash) ? syms.pop : {}
|
|
70
|
+
validates_block(options) do |opts, args|
|
|
71
|
+
syms.all? {|sym| block.call(opts, sym, opts[sym])}
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Validates that the given options were provided by the user.
|
|
76
|
+
def validates_presence_of(*syms)
|
|
77
|
+
validates_each(*syms) {|opts, attr, value| opts["#{attr}_given".to_sym]}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Validates that the value of the given symbols is in the provided object.
|
|
81
|
+
# Takes an options hash that must contain the :in key:
|
|
82
|
+
#
|
|
83
|
+
# validates_inclusion_of :age, :favorite_number, :in => 13..18
|
|
84
|
+
#
|
|
85
|
+
# Also supports :if/:unless like the rails counterparts.
|
|
86
|
+
def validates_inclusion_of(*syms)
|
|
87
|
+
unless syms.last.is_a?(Hash)
|
|
88
|
+
raise ArgumentError.new('validates_inclusion_of takes an options hash')
|
|
89
|
+
end
|
|
90
|
+
options = syms.last
|
|
91
|
+
validates_each(*syms) {|opts, attr, value| options[:in].include?(value)}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
VALID_LENGTH_KEYS = [:in, :within, :maximum, :minimum, :is]
|
|
95
|
+
def extract_length_key(options)
|
|
96
|
+
key_used = VALID_LENGTH_KEYS.find {|key| options.include?(key)}
|
|
97
|
+
if key_used.nil?
|
|
98
|
+
raise ArgumentError.new("One of #{VALID_LENGTH_KEYS.inspect} must be " +
|
|
99
|
+
"provided to validates_length_of")
|
|
100
|
+
end
|
|
101
|
+
key_used
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Validates the length of the string provided as an argument matches the
|
|
105
|
+
# provided constraints on length.
|
|
106
|
+
#
|
|
107
|
+
# @param [Symbol] attr the attribute to validate
|
|
108
|
+
# @param [Hash] options A set of options that specifies the constraint.
|
|
109
|
+
# Must have one of the following: :in, :within, :maximum, :minimum, :is.
|
|
110
|
+
def validates_length_of(attr, options={})
|
|
111
|
+
key_used = extract_length_key options
|
|
112
|
+
validates_block(options) do |opts, args|
|
|
113
|
+
value = opts[attr].size
|
|
114
|
+
numeric_comparison(value, key_used, options[key_used])
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
alias_method :validates_size_of, :validates_length_of
|
|
118
|
+
|
|
119
|
+
# Validates the number of arguments provided with the :in, :within, :maximum,
|
|
120
|
+
# :minimum, and :is relationships. To validate that a user provided at least
|
|
121
|
+
# 2 arguments in a copy command:
|
|
122
|
+
#
|
|
123
|
+
# command "copy" do
|
|
124
|
+
# validates_argument_count :minimum => 2
|
|
125
|
+
# end
|
|
126
|
+
#
|
|
127
|
+
def validates_argument_count(options={})
|
|
128
|
+
key_used = extract_length_key options
|
|
129
|
+
validates_block(options) do |opts, args|
|
|
130
|
+
value = args.size
|
|
131
|
+
numeric_comparison(value, key_used, options[key_used])
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Compares a value to a given constraint and returns whether it matches it
|
|
136
|
+
# or not.
|
|
137
|
+
#
|
|
138
|
+
# @param [Integer] value a numeric value
|
|
139
|
+
# @param [Symbol] key_used the key used for comparison. Either :within,
|
|
140
|
+
# :in, :maximum, :minimum, and :is.
|
|
141
|
+
# @param [Integer, #include?] constraint a value to compare against
|
|
142
|
+
# @return [Boolean]
|
|
143
|
+
def numeric_comparison(value, key_used, constraint)
|
|
144
|
+
if key_used == :in || key_used == :within
|
|
145
|
+
constraint.include?(value)
|
|
146
|
+
elsif key_used == :is
|
|
147
|
+
constraint == value
|
|
148
|
+
elsif key_used == :minimum
|
|
149
|
+
constraint <= value
|
|
150
|
+
elsif key_used == :maximum
|
|
151
|
+
constraint >= value
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Is this a valid set of options and arguments for this command?
|
|
157
|
+
def valid?(opts, args)
|
|
158
|
+
self.class.before_blocks.all? {|block| block.call(opts, args)}
|
|
159
|
+
end
|
|
160
|
+
alias_method :run_before, :valid?
|
|
161
|
+
|
|
162
|
+
def invalid?(opts, args)
|
|
163
|
+
!valid?(opts, args)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def run_after(opts, args)
|
|
167
|
+
self.class.after_blocks.all? {|block| block.call(opts, args)}
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|