mithril 0.2.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/CHANGELOG.md +31 -0
- data/README.md +0 -0
- data/bin/mithril +5 -0
- data/lib/mithril.rb +13 -0
- data/lib/mithril/controllers.rb +7 -0
- data/lib/mithril/controllers/abstract_controller.rb +130 -0
- data/lib/mithril/controllers/mixins.rb +7 -0
- data/lib/mithril/controllers/mixins/actions_base.rb +114 -0
- data/lib/mithril/controllers/mixins/help_actions.rb +46 -0
- data/lib/mithril/controllers/mixins/mixin_with_actions.rb +27 -0
- data/lib/mithril/controllers/proxy_controller.rb +89 -0
- data/lib/mithril/mixin.rb +33 -0
- data/lib/mithril/parsers.rb +7 -0
- data/lib/mithril/parsers/simple_parser.rb +57 -0
- data/lib/mithril/request.rb +11 -0
- data/lib/mithril/version.rb +5 -0
- data/spec/matchers/be_kind_of_spec.rb +50 -0
- data/spec/matchers/construct_spec.rb +49 -0
- data/spec/matchers/respond_to_spec.rb +158 -0
- data/spec/mithril/controllers/_text_controller_helper.rb +81 -0
- data/spec/mithril/controllers/abstract_controller_helper.rb +118 -0
- data/spec/mithril/controllers/abstract_controller_spec.rb +15 -0
- data/spec/mithril/controllers/mixins/actions_base_helper.rb +121 -0
- data/spec/mithril/controllers/mixins/actions_base_spec.rb +18 -0
- data/spec/mithril/controllers/mixins/help_actions_helper.rb +111 -0
- data/spec/mithril/controllers/mixins/help_actions_spec.rb +19 -0
- data/spec/mithril/controllers/mixins/mixin_with_actions_spec.rb +44 -0
- data/spec/mithril/controllers/proxy_controller_helper.rb +111 -0
- data/spec/mithril/controllers/proxy_controller_spec.rb +14 -0
- data/spec/mithril/mixin_helper.rb +54 -0
- data/spec/mithril/mixin_spec.rb +17 -0
- data/spec/mithril/parsers/simple_parser_spec.rb +85 -0
- data/spec/mithril/request_spec.rb +72 -0
- data/spec/mithril_spec.rb +25 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/factories/action_factory.rb +7 -0
- data/spec/support/factories/request_factory.rb +11 -0
- data/spec/support/matchers/be_kind_of.rb +23 -0
- data/spec/support/matchers/construct.rb +49 -0
- data/spec/support/matchers/respond_to.rb +52 -0
- metadata +142 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# lib/mithril/mixin.rb
|
2
|
+
|
3
|
+
module Mithril
|
4
|
+
# Implements module-based inheritance of both class- and instance-level
|
5
|
+
# methods.
|
6
|
+
module Mixin
|
7
|
+
def mixins
|
8
|
+
@mixins ||= []
|
9
|
+
end # accessor mixins
|
10
|
+
|
11
|
+
def mixins=(ary)
|
12
|
+
@mixins = ary
|
13
|
+
end # mutator mixins
|
14
|
+
|
15
|
+
private
|
16
|
+
# Alternative to Module.extend that also provides inheritance of class-level
|
17
|
+
# methods defined through an (optional) ClassMethods module.
|
18
|
+
def mixin(source_module) # :doc:
|
19
|
+
include source_module
|
20
|
+
|
21
|
+
return unless source_module.respond_to? :mixins
|
22
|
+
|
23
|
+
self.mixins = source_module.mixins.dup || []
|
24
|
+
self.mixins << source_module
|
25
|
+
|
26
|
+
self.mixins.each do |mixin|
|
27
|
+
if mixin.const_defined? :ClassMethods
|
28
|
+
extend mixin::ClassMethods
|
29
|
+
end # if
|
30
|
+
end # each
|
31
|
+
end # method mixin
|
32
|
+
end # module Mixin
|
33
|
+
end # module
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# lib/mithril/parsers/simple_parser.rb
|
2
|
+
|
3
|
+
require 'mithril/parsers'
|
4
|
+
|
5
|
+
module Mithril::Parsers
|
6
|
+
class SimpleParser
|
7
|
+
def initialize(actions)
|
8
|
+
@actions = actions
|
9
|
+
end # method initialize
|
10
|
+
|
11
|
+
# Takes a string input and separates into words, then identifies a matching
|
12
|
+
# action (if any) and remaining arguments. Returns both the command and the
|
13
|
+
# arguments array, so usage can be as follows:
|
14
|
+
#
|
15
|
+
# @example With a "say" command:
|
16
|
+
# command, args = parse_command("say Greetings programs!")
|
17
|
+
# #=> command = :say, args = ["greetings", "programs"]
|
18
|
+
# @example With no "hello" command:
|
19
|
+
# command, args = parse_command("Hello world")
|
20
|
+
# #=> command = nil, args = ["hello", "world"]
|
21
|
+
#
|
22
|
+
# @param [String] text Expects a string composed of one or more words,
|
23
|
+
# separated by whitespace or hyphens.
|
24
|
+
# @return [Array] A two-element array consisting of the command and an
|
25
|
+
# array of the remaining text arguments (if any), or [nil, args] if no
|
26
|
+
# matching action was found.
|
27
|
+
def parse_command(text)
|
28
|
+
words = wordify preprocess_input text
|
29
|
+
|
30
|
+
key = nil
|
31
|
+
args = []
|
32
|
+
|
33
|
+
while 0 < words.count
|
34
|
+
key = words.join('_').intern
|
35
|
+
|
36
|
+
return key, args if @actions.has_action? key
|
37
|
+
|
38
|
+
args.unshift words.pop
|
39
|
+
end # while
|
40
|
+
|
41
|
+
return nil, args
|
42
|
+
end # method parse_command
|
43
|
+
|
44
|
+
private
|
45
|
+
# @!visibility public
|
46
|
+
def preprocess_input(text)
|
47
|
+
text.downcase.
|
48
|
+
gsub(/[\"?!\-',.:\(\)\[\]\;]/, ' ').
|
49
|
+
gsub(/(\s+)/, ' ').strip
|
50
|
+
end # method preprocess_input
|
51
|
+
|
52
|
+
# @!visibility public
|
53
|
+
def wordify(text)
|
54
|
+
text.split(/\s+/)
|
55
|
+
end # method wordify
|
56
|
+
end # class
|
57
|
+
end # module
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# spec/matchers/be_kind_of_spec.rb
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe RSpec::Matchers::BuiltIn::BeAKindOf do
|
6
|
+
let :custom_module do Module.new; end
|
7
|
+
let :custom_class do Class.new.tap { |c| c.send :include, custom_module }; end
|
8
|
+
let :custom_subclass do Class.new custom_class; end
|
9
|
+
|
10
|
+
let :string do "string"; end
|
11
|
+
let :module_instance do Object.new.extend custom_module; end
|
12
|
+
let :class_instance do custom_class.new; end
|
13
|
+
let :subclass_instance do custom_subclass.new; end
|
14
|
+
|
15
|
+
describe "with type" do
|
16
|
+
specify { expect(nil).to be_a NilClass }
|
17
|
+
specify { expect(nil).not_to be_a String }
|
18
|
+
|
19
|
+
specify { expect(string).to be_a String }
|
20
|
+
specify { expect(string).not_to be_a custom_class }
|
21
|
+
|
22
|
+
specify { expect(module_instance).to be_a custom_module }
|
23
|
+
specify { expect(module_instance).not_to be_a custom_class }
|
24
|
+
|
25
|
+
specify { expect(class_instance).to be_a custom_module }
|
26
|
+
specify { expect(class_instance).to be_a custom_class }
|
27
|
+
specify { expect(class_instance).not_to be_a String }
|
28
|
+
|
29
|
+
specify { expect(subclass_instance).to be_a custom_module }
|
30
|
+
specify { expect(subclass_instance).to be_a custom_class }
|
31
|
+
specify { expect(subclass_instance).to be_a custom_subclass }
|
32
|
+
specify { expect(subclass_instance).not_to be_a String }
|
33
|
+
end # describe
|
34
|
+
|
35
|
+
describe "with nil" do
|
36
|
+
specify { expect(nil).to be_a nil }
|
37
|
+
specify { expect(string).not_to be_a nil }
|
38
|
+
end # describe
|
39
|
+
|
40
|
+
describe "with array of types" do
|
41
|
+
specify { expect(nil).to be_a [String, nil] }
|
42
|
+
specify { expect(nil).not_to be_a [custom_class, String] }
|
43
|
+
|
44
|
+
specify { expect(string).to be_a [custom_module, String, nil] }
|
45
|
+
specify { expect(string).not_to be_a [custom_subclass, nil] }
|
46
|
+
|
47
|
+
specify { expect(subclass_instance).to be_a [custom_class, String] }
|
48
|
+
specify { expect(subclass_instance).not_to be_a [nil, String] }
|
49
|
+
end # describe
|
50
|
+
end # describe
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# spec/matchers/construct_spec.rb
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe "construct matcher" do
|
6
|
+
let :class_with_no_arguments do Class.new; end
|
7
|
+
let :class_with_arguments do
|
8
|
+
Class.new do def initialize(a, b, c = nil); end; end
|
9
|
+
end # let
|
10
|
+
let :not_a_class do Object.new; end
|
11
|
+
|
12
|
+
specify { expect(class_with_no_arguments).to construct }
|
13
|
+
specify { expect(class_with_arguments).to construct }
|
14
|
+
specify { expect(not_a_class).not_to construct }
|
15
|
+
|
16
|
+
describe "with a fixed number of arguments" do
|
17
|
+
specify { expect(class_with_no_arguments).to construct.
|
18
|
+
with(0).arguments }
|
19
|
+
specify { expect(class_with_no_arguments).not_to construct.
|
20
|
+
with(1).arguments }
|
21
|
+
|
22
|
+
specify { expect(class_with_arguments).not_to construct.
|
23
|
+
with(1).arguments }
|
24
|
+
specify { expect(class_with_arguments).to construct.
|
25
|
+
with(2).arguments }
|
26
|
+
specify { expect(class_with_arguments).to construct.
|
27
|
+
with(3).arguments }
|
28
|
+
specify { expect(class_with_arguments).not_to construct.
|
29
|
+
with(4).arguments }
|
30
|
+
end # describe
|
31
|
+
|
32
|
+
describe "with a range of arguments" do
|
33
|
+
specify { expect(class_with_no_arguments).to construct.
|
34
|
+
with(0..0).arguments }
|
35
|
+
specify { expect(class_with_no_arguments).not_to construct.
|
36
|
+
with(0..1).arguments }
|
37
|
+
specify { expect(class_with_no_arguments).not_to construct.
|
38
|
+
with(1..2).arguments }
|
39
|
+
|
40
|
+
specify { expect(class_with_arguments).not_to construct.
|
41
|
+
with(1..4).arguments }
|
42
|
+
specify { expect(class_with_arguments).not_to construct.
|
43
|
+
with(1..3).arguments }
|
44
|
+
specify { expect(class_with_arguments).not_to construct.
|
45
|
+
with(2..4).arguments }
|
46
|
+
specify { expect(class_with_arguments).to construct.
|
47
|
+
with(2..3).arguments }
|
48
|
+
end # describe
|
49
|
+
end # describe
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# spec/matchers/respond_to_spec.rb
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe RSpec::Matchers::BuiltIn::RespondTo do
|
6
|
+
let :described_class do
|
7
|
+
Class.new do
|
8
|
+
def method_with_no_arguments; end
|
9
|
+
|
10
|
+
def method_with_required_arguments(a, b, c); end
|
11
|
+
|
12
|
+
def method_with_optional_arguments(a, b, c = nil, d = nil); end
|
13
|
+
|
14
|
+
def method_with_variadic_arguments(a, b, c, *rest); end
|
15
|
+
|
16
|
+
def method_with_mixed_arguments(a, b, c = nil, d = nil, *rest); end
|
17
|
+
|
18
|
+
def method_with_yield; yield; end
|
19
|
+
|
20
|
+
def method_with_block_argument(&block); end
|
21
|
+
|
22
|
+
def method_with_block_and_mixed_arguments(a, b = nil, *rest, &block); end
|
23
|
+
end # class
|
24
|
+
end # let
|
25
|
+
let :instance do described_class.new; end
|
26
|
+
|
27
|
+
specify { expect(instance).to respond_to :method_with_no_arguments }
|
28
|
+
specify { expect(instance).to respond_to :method_with_required_arguments }
|
29
|
+
specify { expect(instance).to respond_to :method_with_optional_arguments }
|
30
|
+
specify { expect(instance).to respond_to :method_with_variadic_arguments }
|
31
|
+
specify { expect(instance).to respond_to :method_with_yield }
|
32
|
+
specify { expect(instance).to respond_to :method_with_mixed_arguments }
|
33
|
+
specify { expect(instance).to respond_to :method_with_block_argument }
|
34
|
+
|
35
|
+
specify { expect(instance).not_to respond_to :not_a_method }
|
36
|
+
|
37
|
+
describe "with a fixed number of arguments" do
|
38
|
+
specify { expect(instance).to respond_to(:method_with_no_arguments).
|
39
|
+
with(0).arguments }
|
40
|
+
specify { expect(instance).not_to respond_to(:method_with_no_arguments).
|
41
|
+
with(1).arguments }
|
42
|
+
|
43
|
+
specify { expect(instance).not_to respond_to(:method_with_required_arguments).
|
44
|
+
with(2).arguments }
|
45
|
+
specify { expect(instance).to respond_to(:method_with_required_arguments).
|
46
|
+
with(3).arguments }
|
47
|
+
specify { expect(instance).not_to respond_to(:method_with_required_arguments).
|
48
|
+
with(4).arguments }
|
49
|
+
|
50
|
+
specify { expect(instance).not_to respond_to(:method_with_optional_arguments).
|
51
|
+
with(1).arguments }
|
52
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
53
|
+
with(2).arguments }
|
54
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
55
|
+
with(3).arguments }
|
56
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
57
|
+
with(4).arguments }
|
58
|
+
specify { expect(instance).not_to respond_to(:method_with_optional_arguments).
|
59
|
+
with(5).arguments }
|
60
|
+
|
61
|
+
specify { expect(instance).not_to respond_to(:method_with_variadic_arguments).
|
62
|
+
with(2).arguments }
|
63
|
+
specify { expect(instance).to respond_to(:method_with_variadic_arguments).
|
64
|
+
with(3).arguments }
|
65
|
+
specify { expect(instance).to respond_to(:method_with_variadic_arguments).
|
66
|
+
with(4).arguments }
|
67
|
+
specify { expect(instance).to respond_to(:method_with_variadic_arguments).
|
68
|
+
with(9001).arguments } # IT'S OVER NINE THOUSAND!
|
69
|
+
|
70
|
+
specify { expect(instance).not_to respond_to(:method_with_mixed_arguments).
|
71
|
+
with(1).arguments }
|
72
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
73
|
+
with(2).arguments }
|
74
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
75
|
+
with(3).arguments }
|
76
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
77
|
+
with(4).arguments }
|
78
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
79
|
+
with(5).arguments }
|
80
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
81
|
+
with(9001).arguments } # WHAT?! NINE THOUSAND!
|
82
|
+
end # describe
|
83
|
+
|
84
|
+
describe "with a range of arguments" do
|
85
|
+
specify { expect(instance).to respond_to(:method_with_no_arguments).
|
86
|
+
with(0..0).arguments }
|
87
|
+
specify { expect(instance).not_to respond_to(:method_with_no_arguments).
|
88
|
+
with(0..1).arguments }
|
89
|
+
|
90
|
+
specify { expect(instance).not_to respond_to(:method_with_required_arguments).
|
91
|
+
with(0..3).arguments }
|
92
|
+
specify { expect(instance).not_to respond_to(:method_with_required_arguments).
|
93
|
+
with(2..3).arguments }
|
94
|
+
specify { expect(instance).not_to respond_to(:method_with_required_arguments).
|
95
|
+
with(3..4).arguments }
|
96
|
+
specify { expect(instance).to respond_to(:method_with_required_arguments).
|
97
|
+
with(3..3).arguments }
|
98
|
+
|
99
|
+
specify { expect(instance).not_to respond_to(:method_with_optional_arguments).
|
100
|
+
with(0..4).arguments }
|
101
|
+
specify { expect(instance).not_to respond_to(:method_with_optional_arguments).
|
102
|
+
with(2..5).arguments }
|
103
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
104
|
+
with(2..2).arguments }
|
105
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
106
|
+
with(2..3).arguments }
|
107
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
108
|
+
with(2..4).arguments }
|
109
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
110
|
+
with(3..4).arguments }
|
111
|
+
specify { expect(instance).to respond_to(:method_with_optional_arguments).
|
112
|
+
with(4..4).arguments }
|
113
|
+
|
114
|
+
specify { expect(instance).not_to respond_to(:method_with_variadic_arguments).
|
115
|
+
with(0..4).arguments }
|
116
|
+
specify { expect(instance).not_to respond_to(:method_with_variadic_arguments).
|
117
|
+
with(2..4).arguments }
|
118
|
+
specify { expect(instance).to respond_to(:method_with_variadic_arguments).
|
119
|
+
with(3..4).arguments }
|
120
|
+
specify { expect(instance).to respond_to(:method_with_variadic_arguments).
|
121
|
+
with(5..9).arguments }
|
122
|
+
specify { expect(instance).to respond_to(:method_with_variadic_arguments).
|
123
|
+
with(3..9001).arguments } # VEGETA, WHAT DOES...NEVER MIND, JOKE'S OVER
|
124
|
+
|
125
|
+
specify { expect(instance).not_to respond_to(:method_with_mixed_arguments).
|
126
|
+
with(0..5).arguments }
|
127
|
+
specify { expect(instance).not_to respond_to(:method_with_mixed_arguments).
|
128
|
+
with(1..5).arguments }
|
129
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
130
|
+
with(2..5).arguments }
|
131
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
132
|
+
with(3..5).arguments }
|
133
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
134
|
+
with(4..5).arguments }
|
135
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
136
|
+
with(5..5).arguments }
|
137
|
+
specify { expect(instance).to respond_to(:method_with_mixed_arguments).
|
138
|
+
with(2..9001).arguments } # THERE'S NO WAY THAT CAN BE RIGHT. CAN IT?!?
|
139
|
+
end # describe
|
140
|
+
|
141
|
+
describe "with a block" do
|
142
|
+
specify { expect(instance).not_to respond_to(:method_with_no_arguments).
|
143
|
+
with.a_block }
|
144
|
+
|
145
|
+
specify { expect(instance).not_to respond_to(:method_with_yield).
|
146
|
+
with.a_block }
|
147
|
+
|
148
|
+
specify { expect(instance).to respond_to(:method_with_block_argument).
|
149
|
+
with.a_block }
|
150
|
+
specify { expect(instance).to respond_to(:method_with_block_argument).
|
151
|
+
with(0).arguments.and.a_block }
|
152
|
+
|
153
|
+
specify { expect(instance).to respond_to(:method_with_block_and_mixed_arguments).
|
154
|
+
with.a_block }
|
155
|
+
specify { expect(instance).to respond_to(:method_with_block_and_mixed_arguments).
|
156
|
+
with(2..9001).arguments.and.a_block } # FINE, FINE. KILLJOYS.
|
157
|
+
end # describe
|
158
|
+
end # describe
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# spec/controllers/text_controller_helper.rb
|
2
|
+
|
3
|
+
require 'mithril/controllers/abstract_controller_helper'
|
4
|
+
|
5
|
+
shared_examples_for "Mithril::Controllers::_TextController" do
|
6
|
+
it_behaves_like Mithril::Controllers::AbstractController
|
7
|
+
|
8
|
+
let :input do "text input"; end
|
9
|
+
|
10
|
+
describe :parser do
|
11
|
+
specify { expect(instance.parser).to be_a Mithril::Parsers::SimpleParser }
|
12
|
+
end # describe
|
13
|
+
|
14
|
+
describe :parse_command do
|
15
|
+
specify { expect(instance.parse_command input).to be_a Array }
|
16
|
+
|
17
|
+
specify "returns nil" do
|
18
|
+
command, args = instance.parse_command input
|
19
|
+
expect(command).to be nil
|
20
|
+
end # specify
|
21
|
+
end # describe
|
22
|
+
|
23
|
+
describe :command_missing do
|
24
|
+
specify "returns the text with a helpful message" do
|
25
|
+
output = instance.command_missing input
|
26
|
+
expect(output).to match /don't know how/
|
27
|
+
expect(output).to match /#{input}/
|
28
|
+
end # specify
|
29
|
+
end # describe
|
30
|
+
|
31
|
+
describe :invoke_command do
|
32
|
+
specify "returns the text with a helpful message" do
|
33
|
+
output = instance.invoke_command input
|
34
|
+
expect(output).to match /don't know how/
|
35
|
+
expect(output).to match /#{input}/
|
36
|
+
end # specify
|
37
|
+
end # describe
|
38
|
+
|
39
|
+
context "with actions defined" do
|
40
|
+
let :command do FactoryGirl.generate :action_key; end
|
41
|
+
let :arguments do %w(arguments for command); end
|
42
|
+
|
43
|
+
before :each do
|
44
|
+
described_class.define_action command do |session, args| args.join(' '); end
|
45
|
+
end # before each
|
46
|
+
|
47
|
+
specify { expect(instance.can_invoke? command.to_s).to be true }
|
48
|
+
|
49
|
+
describe :invoke_command do
|
50
|
+
let :text do "#{command} #{arguments.join(' ')}"; end
|
51
|
+
|
52
|
+
specify "invokes matching action" do
|
53
|
+
instance.should_receive(:invoke_action).with(command, arguments).and_call_original
|
54
|
+
instance.should_receive(:"action_#{command}").with(request.session, arguments).and_call_original
|
55
|
+
instance.invoke_command text
|
56
|
+
end # specify
|
57
|
+
|
58
|
+
specify { expect(instance.invoke_command text).to eq arguments.join(' ') }
|
59
|
+
|
60
|
+
context "with a non-matching command" do
|
61
|
+
let :non_matching do FactoryGirl.generate :action_key; end
|
62
|
+
|
63
|
+
specify { expect(instance.invoke_command non_matching.to_s).to match /don't know how/i }
|
64
|
+
end # context
|
65
|
+
end # describe
|
66
|
+
end # context
|
67
|
+
|
68
|
+
describe "empty actions" do
|
69
|
+
def self.input
|
70
|
+
chars, words = [*"a".."z", *"0".."9"], [""] * 5
|
71
|
+
5.times do |i|
|
72
|
+
word = ""
|
73
|
+
(6 + rand(10)).times do word << chars[rand(36)]; end
|
74
|
+
words[i] = word
|
75
|
+
end # times
|
76
|
+
words.join " "
|
77
|
+
end # helper input
|
78
|
+
|
79
|
+
it_behaves_like "Mithril::Controllers::AbstractController#empty_actions", input
|
80
|
+
end # describe
|
81
|
+
end # describe
|