matrioska 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ pkg
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
@@ -0,0 +1,4 @@
1
+ # develop
2
+
3
+ # Version 0.0.1
4
+ * First official release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in plugin-template.gemspec
4
+ gemspec
@@ -0,0 +1,131 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ matrioska (0.0.1)
5
+ activesupport (>= 3.0.10)
6
+ adhearsion (~> 2.2)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ activesupport (3.2.10)
12
+ i18n (~> 0.6)
13
+ multi_json (~> 1.0)
14
+ adhearsion (2.2.0)
15
+ activesupport (~> 3.0)
16
+ adhearsion-loquacious (~> 1.9)
17
+ bundler (~> 1.0)
18
+ celluloid (~> 0.12, >= 0.12.1)
19
+ countdownlatch
20
+ deep_merge
21
+ ffi (~> 1.0)
22
+ future-resource (~> 1.0)
23
+ girl_friday
24
+ has-guarded-handlers (~> 1.5)
25
+ logging (~> 1.8)
26
+ pry
27
+ punchblock (~> 1.4)
28
+ rake
29
+ ruby_speech (~> 1.0)
30
+ thor
31
+ adhearsion-loquacious (1.9.3)
32
+ blather (0.8.2)
33
+ activesupport (>= 2.3.11)
34
+ eventmachine (>= 1.0.0)
35
+ girl_friday
36
+ niceogiri (~> 1.0)
37
+ nokogiri (~> 1.5, >= 1.5.6)
38
+ celluloid (0.12.4)
39
+ facter (>= 1.6.12)
40
+ timers (>= 1.0.0)
41
+ celluloid-io (0.12.1)
42
+ celluloid (~> 0.12.0)
43
+ nio4r (>= 0.4.0)
44
+ coderay (1.0.8)
45
+ connection_pool (0.9.3)
46
+ countdownlatch (1.0.0)
47
+ deep_merge (1.0.0)
48
+ diff-lcs (1.1.3)
49
+ eventmachine (1.0.0)
50
+ facter (1.6.17)
51
+ ffi (1.2.0)
52
+ future-resource (1.0.0)
53
+ girl_friday (0.11.1)
54
+ connection_pool (~> 0.9.0)
55
+ rubinius-actor
56
+ guard (1.5.0)
57
+ listen (>= 0.4.2)
58
+ lumberjack (>= 1.0.2)
59
+ pry (>= 0.9.10)
60
+ thor (>= 0.14.6)
61
+ guard-rspec (2.1.0)
62
+ guard (>= 1.1)
63
+ rspec (~> 2.11)
64
+ has-guarded-handlers (1.5.0)
65
+ i18n (0.6.1)
66
+ json (1.7.5)
67
+ listen (0.5.3)
68
+ little-plugger (1.1.3)
69
+ logging (1.8.1)
70
+ little-plugger (>= 1.1.3)
71
+ multi_json (>= 1.3.6)
72
+ lumberjack (1.0.2)
73
+ method_source (0.8.1)
74
+ multi_json (1.5.0)
75
+ niceogiri (1.1.1)
76
+ nokogiri (~> 1.5)
77
+ nio4r (0.4.3)
78
+ nokogiri (1.5.6)
79
+ pry (0.9.10)
80
+ coderay (~> 1.0.5)
81
+ method_source (~> 0.8)
82
+ slop (~> 3.3.1)
83
+ punchblock (1.7.1)
84
+ activesupport (~> 3.0)
85
+ blather (>= 0.7.0)
86
+ celluloid (~> 0.12, >= 0.12.3)
87
+ future-resource (~> 1.0)
88
+ has-guarded-handlers (~> 1.5)
89
+ niceogiri (~> 1.1)
90
+ ruby_ami (~> 1.2, >= 1.2.1)
91
+ ruby_fs (~> 1.0)
92
+ ruby_speech (~> 1.0)
93
+ state_machine (~> 1.0)
94
+ rake (0.9.2.2)
95
+ rspec (2.11.0)
96
+ rspec-core (~> 2.11.0)
97
+ rspec-expectations (~> 2.11.0)
98
+ rspec-mocks (~> 2.11.0)
99
+ rspec-core (2.11.1)
100
+ rspec-expectations (2.11.3)
101
+ diff-lcs (~> 1.1.3)
102
+ rspec-mocks (2.11.3)
103
+ rubinius-actor (0.0.2)
104
+ rubinius-core-api
105
+ rubinius-core-api (0.0.1)
106
+ ruby_ami (1.2.6)
107
+ celluloid-io (~> 0.12.0)
108
+ countdownlatch (~> 1.0)
109
+ future-resource
110
+ girl_friday
111
+ ruby_fs (1.0.3)
112
+ celluloid-io (~> 0.12.0)
113
+ json
114
+ ruby_speech (1.0.2)
115
+ activesupport (>= 3.0.7)
116
+ niceogiri (~> 1.1, >= 1.1.1)
117
+ nokogiri (~> 1.5, >= 1.5.6)
118
+ slop (3.3.3)
119
+ state_machine (1.1.2)
120
+ thor (0.16.0)
121
+ timers (1.0.2)
122
+
123
+ PLATFORMS
124
+ ruby
125
+
126
+ DEPENDENCIES
127
+ bundler (~> 1.0)
128
+ guard-rspec
129
+ matrioska!
130
+ rake
131
+ rspec (~> 2.5)
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara request specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2012 Adhearsion Foundation Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # Matrioska
2
+
3
+ Matrioska is an Adhearsion plugin for running in-call apps at the press of a DTMF.
4
+
5
+ By mapping controllers or blocks to the desired applications, a listener object waits for DTMF and reacts by executing the specified payload.
6
+
7
+ ## Usage Example
8
+
9
+ ```ruby
10
+ #inside your controller
11
+ runner = Matrioska::AppRunner.new self
12
+ runner.map_app 3 do
13
+ logger.info "hi there!"
14
+ end
15
+ runner.map_app 5, AppController
16
+
17
+ call.on_end do
18
+ runner.stop
19
+ end
20
+
21
+ runner.start
22
+ ```
23
+
24
+ ### Author
25
+
26
+ Original author: [Luca Pradovera](https://github.com/polysics)
27
+
28
+ ### Links
29
+
30
+ * [Adhearsion](http://adhearsion.com)
31
+ * [Source](https://github.com/polysics/matrioska)
32
+ * [Bug Tracker](https://github.com/polysics/matrioska/issues)
33
+
34
+ ### Note on Patches/Pull Requests
35
+
36
+ * Fork the project.
37
+ * Make your feature addition or bug fix.
38
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
39
+ * Commit, do not mess with rakefile, version, or history.
40
+ * If you want to have your own version, that is fine but bump version in a commit by itself so I can ignore when I pull
41
+ * Send me a pull request. Bonus points for topic branches.
42
+
43
+ ### Copyright
44
+
45
+ Copyright (c) 2013 Adhearsion Foundation Inc. MIT license (see LICENSE for details).
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ Matrioska = Module.new
2
+ require "matrioska/version"
3
+ require "matrioska/plugin"
4
+ require "matrioska/app_runner"
@@ -0,0 +1,65 @@
1
+ module Matrioska
2
+ class AppRunner
3
+ include Adhearsion::CallController::Utility
4
+
5
+ def initialize(call)
6
+ @call = call
7
+ @app_map = {}
8
+ end
9
+
10
+ def start
11
+ component = Punchblock::Component::Input.new({ :mode => :dtmf,
12
+ :grammar => {
13
+ :value => grammar_accept
14
+ }
15
+ })
16
+ component.register_event_handler Punchblock::Event::Complete do |event|
17
+ handle_input_complete event
18
+ end
19
+ @call.write_and_await_response component
20
+ end
21
+
22
+ def app_map
23
+ @app_map
24
+ end
25
+
26
+ def map_app(digit, controller=nil, &block)
27
+ digit = digit.to_s
28
+ range = "1234567890*#"
29
+
30
+ unless range.include?(digit) && digit.size == 1
31
+ raise ArgumentError, "The first argument should be a single digit String or number in the range 1234567890*#"
32
+ end
33
+
34
+ payload = if block_given?
35
+ raise ArgumentError, "You cannot specify both a block and a controller name." if controller.is_a? Class
36
+ block
37
+ else
38
+ raise ArgumentError, "You need to provide a block or a controller name." unless controller.is_a? Class
39
+ controller
40
+ end
41
+
42
+ @app_map[digit] = payload
43
+ end
44
+
45
+ def match_and_run(digit)
46
+ if match = @app_map[digit]
47
+ Adhearsion.logger.info "#match_and_run called with #{digit}"
48
+ callback = lambda {|call| start }
49
+
50
+ @call.execute_controller(nil, callback, &match) if match.is_a? Proc
51
+ if match.is_a? Class
52
+ payload = match.new(@call)
53
+ @call.execute_controller(payload, callback)
54
+ end
55
+ end
56
+ start
57
+ end
58
+
59
+ def handle_input_complete(event)
60
+ result = event.reason.respond_to?(:utterance) ? event.reason.utterance : nil
61
+ digit = parse_dtmf result
62
+ match_and_run digit
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,29 @@
1
+ module Matrioska
2
+ class Plugin < Adhearsion::Plugin
3
+ # Actions to perform when the plugin is loaded
4
+ #
5
+ init :matrioska do
6
+ logger.warn "Matrioska has been loaded"
7
+ end
8
+
9
+ # Basic configuration for the plugin
10
+ #
11
+ config :matrioska do
12
+ greeting "Hello", :desc => "What to use to greet users"
13
+ end
14
+
15
+ # Defining a Rake task is easy
16
+ # The following can be invoked with:
17
+ # rake plugin_demo:info
18
+ #
19
+ tasks do
20
+ namespace :matrioska do
21
+ desc "Prints the PluginTemplate information"
22
+ task :info do
23
+ STDOUT.puts "Matrioska plugin v. #{VERSION}"
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Matrioska
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "matrioska/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "matrioska"
7
+ s.version = Matrioska::VERSION
8
+ s.authors = ["Luca Pradovera"]
9
+ s.email = ["lpradovera@mojolingo.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Adhearsion plugin for in-call apps}
12
+ s.description = %q{Adhearsion plugin for in-call apps. Provides a features-style interface to run applications in calls.}
13
+
14
+ s.rubyforge_project = "matrioska"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_runtime_dependency %q<adhearsion>, ["~> 2.2"]
21
+ s.add_runtime_dependency %q<activesupport>, [">= 3.0.10"]
22
+
23
+ s.add_development_dependency %q<bundler>, ["~> 1.0"]
24
+ s.add_development_dependency %q<rspec>, ["~> 2.5"]
25
+ s.add_development_dependency %q<rake>, [">= 0"]
26
+ s.add_development_dependency %q<guard-rspec>
27
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ module Matrioska
4
+ describe AppRunner do
5
+ let(:mock_call) { mock('Call') }
6
+ subject { AppRunner.new mock_call }
7
+ class MockController < Adhearsion::CallController; end
8
+
9
+ describe "#start" do
10
+ let(:grxml) {
11
+ RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
12
+ rule id: 'inputdigits', scope: 'public' do
13
+ one_of do
14
+ 0.upto(9) { |d| item { d.to_s } }
15
+ item { "#" }
16
+ item { "*" }
17
+ end
18
+ end
19
+ end
20
+ }
21
+
22
+ let(:input_component) {
23
+ Punchblock::Component::Input.new(
24
+ { :mode => :dtmf,
25
+ :grammar => {
26
+ :value => grxml.to_s
27
+ }
28
+ }
29
+ )
30
+ }
31
+
32
+ it "should start the appropriate component" do
33
+ mock_call.should_receive(:write_and_await_response).with(input_component)
34
+ subject.start
35
+ end
36
+ end
37
+
38
+ describe "#map_app" do
39
+ context "with invalid input" do
40
+ let(:too_long) { "ab" }
41
+ let(:wrong) { "a" }
42
+ it "should raise if the first argument is not a single digit string in the range" do
43
+ expect { subject.map_app(too_long){} }.to raise_error ArgumentError, "The first argument should be a single digit String or number in the range 1234567890*#"
44
+ expect { subject.map_app(wrong){} }.to raise_error ArgumentError, "The first argument should be a single digit String or number in the range 1234567890*#"
45
+ end
46
+
47
+ it "raises if called without either a class or a block" do
48
+ expect { subject.map_app 1 }.to raise_error ArgumentError, "You need to provide a block or a controller name."
49
+ end
50
+
51
+ it "raises if passed both a class and a block" do
52
+ expect { subject.map_app(1, Object){} }.to raise_error ArgumentError, "You cannot specify both a block and a controller name."
53
+ end
54
+ end
55
+
56
+ context "with valid input" do
57
+ it "properly sets the map for a block" do
58
+ subject.map_app(3) { p "foo" }
59
+ subject.app_map["3"].should be_a Proc
60
+ end
61
+ it "properly sets the map for a class" do
62
+ subject.map_app(3, Object)
63
+ subject.app_map["3"].should be_a Class
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#match_and_run" do
69
+ before do
70
+ subject.map_app(3) { p "foo" }
71
+ subject.map_app(5, MockController)
72
+ end
73
+
74
+ it "does nothing if there is no match, and restarts the launcher" do
75
+ mock_call.should_receive(:execute_controller).never
76
+ subject.should_receive(:start).once
77
+ subject.match_and_run("4")
78
+ end
79
+
80
+ it "executes the block if the payload is a Proc" do
81
+ mock_call.should_receive(:execute_controller).once.with(&subject.app_map["3"])
82
+ subject.should_receive(:start).once
83
+ subject.match_and_run("3")
84
+ end
85
+ it "executes the controller if the payload is a Class" do
86
+ mock_call.should_receive(:execute_controller).once.with(kind_of(MockController), kind_of(Proc))
87
+ subject.should_receive(:start).once
88
+ subject.match_and_run("5")
89
+ end
90
+ end
91
+
92
+ describe "#handle_input_complete" do
93
+ let(:mock_event) { mock('Event', :reason => mock('Reason', :utterance => "dtmf-5")) }
94
+ it "runs #match_and_run" do
95
+ subject.should_receive(:match_and_run).with("5").once
96
+ subject.handle_input_complete(mock_event)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,11 @@
1
+ require 'adhearsion'
2
+ require 'matrioska'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ config.tty = true
7
+
8
+ config.filter_run :focus => true
9
+ config.run_all_when_everything_filtered = true
10
+ end
11
+
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: matrioska
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Luca Pradovera
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: adhearsion
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.2'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 3.0.10
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.10
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '2.5'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '2.5'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: guard-rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Adhearsion plugin for in-call apps. Provides a features-style interface
111
+ to run applications in calls.
112
+ email:
113
+ - lpradovera@mojolingo.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rspec
120
+ - CHANGELOG.md
121
+ - Gemfile
122
+ - Gemfile.lock
123
+ - Guardfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - lib/matrioska.rb
128
+ - lib/matrioska/app_runner.rb
129
+ - lib/matrioska/plugin.rb
130
+ - lib/matrioska/version.rb
131
+ - matrioska.gemspec
132
+ - spec/matrioska/app_runner_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: ''
135
+ licenses: []
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project: matrioska
154
+ rubygems_version: 1.8.24
155
+ signing_key:
156
+ specification_version: 3
157
+ summary: Adhearsion plugin for in-call apps
158
+ test_files:
159
+ - spec/matrioska/app_runner_spec.rb
160
+ - spec/spec_helper.rb
161
+ has_rdoc: