chaperone 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ coverage
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in chaperone.gemspec
4
+ gem 'rake'
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Matthew Werner
2
+
3
+ MIT License
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.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # Chaperone
2
+
3
+ Getting as close to automated as we can.
4
+
5
+ Sometimes there are processes that just can't be automated.
6
+ Chaperone is a CLI for watching over someone as they go
7
+ through a process that has human-driven components.
8
+ These are processes such as deployment or software
9
+ installation. The gem does not actually execute the
10
+ commands, but rather leaves it to the person following
11
+ the guide to do so.
12
+
13
+ ## Automation > Chaperone
14
+
15
+ Bear in mind that you should prefer automation to chaperone
16
+ whenever possible. If you find the steps you're writing for
17
+ chaperone could be safely executed within a script, chaperone
18
+ is probably not the appropriate place for that process.
19
+
20
+ ## Usage
21
+
22
+ Chaperone includes a `Guide` class which you inherit from. This
23
+ guide provides a DSL that allows you to easily produce multi-step
24
+ functionality with common informational displays as the user progresses
25
+ through a given guide.
26
+
27
+ After you have defined your guide, you simply call `MyGuide.new.start` to begin
28
+
29
+ #### Providing reference info
30
+
31
+ A defined `URL` constant is displayed at the start of the guide
32
+ which points to a more thorough explanation of what's happening.
33
+ It's rare that a chaperone guide can give all the backstory needed,
34
+ so it's handy to let the guidee know where they can get more info.
35
+
36
+ #### Defining steps
37
+
38
+ The `STEPS` constant is an array of strings that defines the names
39
+ of the step methods and their order. Each step string must correspond
40
+ to a method on the class.
41
+
42
+ #### Initialization Options
43
+
44
+ `step` will let you specify the number of the step you want to start on.
45
+ Useful when you are continuing a previously exited guide.
46
+
47
+ `steps` lets you define the array of steps your guide will use. This list
48
+ is normally defined in the `STEPS` constant, but if you have a specific case
49
+ where you only want to run through a subset of steps, this is the best way to
50
+ accomplish that.
51
+
52
+ ## Prompt
53
+
54
+ Each step is rendered using a `prompt` block. The prompt accepts a few
55
+ types of calls that vary depending on what type of information you want
56
+ to display on the screen. These calls vary the visual presentation of
57
+ the content as well as it's order
58
+
59
+ #### Options
60
+
61
+ - `padding` - Specifies if there should be any extra spaces in the prompt (Boolean, default: true)
62
+ - `question` - Specifies if there should be a blocking actions prompt (Boolean, default: true)
63
+
64
+ #### Prompt DSL
65
+
66
+ - `title` A brief message explaining this step
67
+ - `needs` The requirement to continue
68
+ - `current` What the guidee is currently using related to the needs
69
+ - `notes` A plain block of text
70
+ - `code` Highlighted block of exact syntax that they can copy and paste
71
+ - `question` The text displayed on the action prompt
72
+
73
+ #### Actions
74
+
75
+ Each prompt is blocked by a command line input:
76
+
77
+ [c]ontinue, e[x]it, [r]etry
78
+
79
+ If you passed a question into the prompt block, you'll see it before the actions:
80
+
81
+ Ready to continue? [c]ontinue, e[x]it, [r]etry
82
+
83
+ The default is to continue, retry is handy for things like git branch checks which
84
+ a user can update in another terminal and confirm the change is recognized.
85
+
86
+ ## Example
87
+
88
+ version = CommandLine.new('ruby', '-v').run.gsub("\n",'')
89
+ prompt do |p|
90
+ p.title = 'Ruby Version Check'
91
+ p.needs = 'ruby 1.9.3[Any Patch Level]'
92
+ p.notes = '1.8.7 is not supported, sorry.'
93
+ p.current = version
94
+ p.code = 'rvm use 1.9.3'
95
+ p.question = 'Using the right version?'
96
+ end
97
+
98
+ To see a full guide example, see the [`deploy.rb`](https://github.com/mwerner/chaperone/blob/master/examples/deploy.rb) file in the repository's `examples` dir
99
+
100
+ ## Libraries
101
+
102
+ The `Guide` class includes the [cocaine](https://github.com/thoughtbot/cocaine)
103
+ and [highline](https://github.com/JEG2/highline) libraries. Go nuts.
104
+
105
+ ## Future
106
+
107
+ There are a few things I'm hoping to include as a part of this gem
108
+
109
+ - Delivering guide execution reports to a remote server
110
+ - Error reporting to catch failed guide execution in disparate locations
111
+ - A central source for guide distribution
112
+
113
+ ## Contributing
114
+
115
+ 1. Fork it
116
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
117
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
118
+ 4. Push to the branch (`git push origin my-new-feature`)
119
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/chaperone.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'chaperone/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "chaperone"
8
+ gem.version = Chaperone::VERSION
9
+ gem.authors = ["Matthew Werner"]
10
+ gem.email = ["mwerner@zendesk.com"]
11
+ gem.description = %q{Guides you step by step through the things you can mess up}
12
+ gem.summary = %q{Guides you step by step through the things you can mess up}
13
+ gem.license = 'MIT'
14
+ gem.homepage = "https://github.com/mwerner/chaperone"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_development_dependency 'rspec'
22
+ gem.add_development_dependency 'simplecov'
23
+ gem.add_development_dependency 'mocha'
24
+
25
+ gem.add_runtime_dependency 'thor'
26
+ gem.add_runtime_dependency 'cocaine'
27
+ gem.add_runtime_dependency 'activesupport'
28
+ gem.add_runtime_dependency 'highline'
29
+
30
+ end
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'chaperone'
3
+
4
+ class Deploy < Chaperone::Guide
5
+
6
+ URL = 'https://github.com/mwerner/chaperone'
7
+ STEPS = %w[
8
+ check_ruby_version
9
+ execute_capistrano
10
+ tag_release_version
11
+ notify_flowdock
12
+ ]
13
+
14
+ protected
15
+
16
+ def check_ruby_version
17
+ version = CommandLine.new('ruby', '-v').run.gsub("\n",'')
18
+
19
+ prompt do |p|
20
+ p.title = 'Ruby Version Check'
21
+ p.needs = 'ruby 1.9.3[Any Patch Level]'
22
+ p.current = version
23
+ p.code = 'rvm use 1.9.3'
24
+ end
25
+ end
26
+
27
+ def execute_capistrano
28
+ prompt do |p|
29
+ p.title = 'Run capistrano task'
30
+ p.code = 'bundle exec cap production deploy'
31
+ p.notes = %{
32
+ The script can be found in config/deploy/production.rb
33
+ }
34
+ end
35
+ end
36
+
37
+ def tag_release_version
38
+ latest = CommandLine.new('git describe --abbrev=0 --tags').run.gsub("\n",'') rescue 'Unable to determine'
39
+
40
+ prompt(question: false) do |p|
41
+ p.title = 'Tagging the release'
42
+ p.notes = %{
43
+ - This should be the next unreleased tag in the current Changelog.md
44
+ Latest Deployed Version: #{status(latest)}
45
+ }
46
+ end
47
+
48
+ version = ask(strong('The version youre deploying:')).to_s
49
+ prompt do |p|
50
+ p.code = %{
51
+ git tag -a #{version}
52
+ git push origin #{version}
53
+ }
54
+ end
55
+ end
56
+
57
+ def notify_flowdock
58
+ prompt do |p|
59
+ p.title = 'Notify flowdock chat'
60
+ p.code = '@all just deployed master to production'
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ Deploy.new.start
@@ -0,0 +1,88 @@
1
+ module Chaperone
2
+ class Guide
3
+ include Cocaine
4
+ include Output
5
+ include HighlineConfig
6
+
7
+ attr_accessor :steps, :current_step, :iteration, :url
8
+
9
+ STEPS = ['no_steps_defined']
10
+ URL = 'https://github.com/mwerner/chaperone'
11
+
12
+ def initialize(opts={})
13
+ @steps = opts[:steps] || self.class::STEPS
14
+ @url = self.class::URL
15
+ @iteration = 0
16
+ @current_step = opts[:step].to_i || 0
17
+ end
18
+
19
+ def start
20
+ welcome!
21
+
22
+ (0..steps.length-1).each do |step|
23
+ @iteration = step
24
+
25
+ if current_step > iteration
26
+ skip_step!
27
+ next
28
+ end
29
+
30
+ break unless execute_step(steps[iteration].to_sym)
31
+ complete_step!
32
+ end
33
+
34
+ complete!
35
+ end
36
+
37
+ protected
38
+
39
+ def no_steps_defined
40
+ prompt(question: false) do |p|
41
+ p.title = "No Steps are defined for #{self.class.to_s}"
42
+ end
43
+ end
44
+
45
+ def execute_step(step, proceed=true)
46
+ unless self.respond_to?(step)
47
+ output "WARNING: #{step} is not defined"
48
+ return
49
+ end
50
+
51
+ loop do
52
+ case send(step)
53
+ when 'r'; next
54
+ when 'x'; proceed = false
55
+ end
56
+
57
+ break
58
+ end
59
+
60
+ proceed
61
+ end
62
+
63
+ private
64
+
65
+ def prompt(opts={}, &config)
66
+ Prompt.new(opts, &config).render
67
+ end
68
+
69
+ def welcome!
70
+ output '==> Begin'
71
+ output "==> Reference: #{url}" if url
72
+ end
73
+
74
+ def complete_step!
75
+ @current_step += 1
76
+ output notice("==> [#{iteration}] Completed Step")
77
+ end
78
+
79
+ def skip_step!
80
+ output notice("==> Skipping [#{iteration}] #{steps[iteration].gsub('_',' ')}")
81
+ end
82
+
83
+ def complete!
84
+ output "==> Finished"
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,44 @@
1
+ module Chaperone
2
+ class Prompt
3
+ include Output
4
+ include HighlineConfig
5
+
6
+ attr_accessor :title, :notes, :needs, :current, :code, :question, :config
7
+
8
+ def initialize(config={})
9
+ @config = {padding: true, question: true}.merge(config)
10
+ yield(self) if block_given?
11
+ end
12
+
13
+ def render
14
+ output body
15
+ return unless has_question?
16
+ ask strong("#{question} [c]ontinue, [r]etry, e[x]it".squeeze(' '))
17
+ end
18
+
19
+ def lines
20
+ sections = []
21
+ sections << action( title ) if title
22
+ sections << notes if notes
23
+ sections << "#{requirement('Required:')} #{needs}" if needs
24
+ sections << "#{status('Current:')} #{current}" if current
25
+ sections << direction("\n #{code}") if code
26
+ sections
27
+ end
28
+
29
+ def body
30
+ text = lines.join("\n ")
31
+ text = "\n#{text}\n\n" if has_padding?
32
+ text.squeeze(' ')
33
+ end
34
+
35
+ def has_padding?
36
+ !!config[:padding]
37
+ end
38
+
39
+ def has_question?
40
+ !!config[:question]
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module Chaperone
2
+ VERSION = "0.0.1"
3
+ end
data/lib/chaperone.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'cocaine'
2
+ require 'chaperone/version'
3
+ require 'highline/import'
4
+
5
+ module HighlineConfig
6
+ COLORS = [:status, :notice, :action, :error, :requirement, :strong, :direction]
7
+
8
+ HighLine.color_scheme = HighLine::ColorScheme.new do |scheme|
9
+ scheme[:action] = [ :bold, :yellow, :on_black ]
10
+ scheme[:notice] = [ :green ]
11
+ scheme[:status] = [ :bold, :blue ]
12
+ scheme[:error] = [ :red ]
13
+ scheme[:direction] = [ :bold, :black, :on_gray ]
14
+ scheme[:strong] = [ :gray, :bold ]
15
+ scheme[:requirement] = [ :bold, :cyan ]
16
+ end
17
+
18
+ COLORS.each do |hue|
19
+ define_method(hue.to_sym) do |message|
20
+ "<%= color('#{message}', :#{hue})%>"
21
+ end
22
+ end
23
+ end
24
+
25
+ module Output
26
+ def output(message)
27
+ say(message) unless ENV['env'] == 'test'
28
+ end
29
+ end
30
+
31
+ module Chaperone
32
+ autoload :Prompt, 'chaperone/prompt'
33
+ autoload :Guide, 'chaperone/guide'
34
+
35
+ module Guides
36
+ autoload :Brew, 'chaperone/guides/brew'
37
+ end
38
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Guide do
4
+
5
+ context '#initialize' do
6
+ it 'defaults step to 0' do
7
+ Guide.new.current_step.should eq(0)
8
+ end
9
+
10
+ it 'accepts step param' do
11
+ guide = Guide.new(step: 2)
12
+ guide.current_step.should eq(2)
13
+ guide.start
14
+ end
15
+ end
16
+
17
+ context '#start' do
18
+ let(:guide){Guide.new}
19
+
20
+ it 'calls welcome and complete' do
21
+ Guide.any_instance.expects(:welcome!).once
22
+ Guide.any_instance.expects(:complete!).once
23
+ guide.start
24
+ end
25
+
26
+ it 'runs no_steps_defined when no steps are defined' do
27
+ Guide.any_instance.expects(:no_steps_defined).once
28
+ guide.start
29
+ end
30
+
31
+ it 'provides the chaperone url if none is defined' do
32
+ guide.url.should eq(Guide::URL)
33
+ end
34
+
35
+ context 'with steps' do
36
+ let(:guide){Guide.new(steps: ['a','b'])}
37
+ let(:stubbed_guide){
38
+ guide.stubs(:a)
39
+ guide.stubs(:b)
40
+ }
41
+
42
+ it 'warns on an undefined step' do
43
+ expect{ guide.start }.to_not raise_error
44
+ end
45
+
46
+ it 'runs each step' do
47
+ stubbed_guide.expects(:a).once
48
+ stubbed_guide.expects(:b).once
49
+ guide.start
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Guide do
4
+ let(:attrs){%w(title notes needs current code)}
5
+ context '#initialize' do
6
+ it 'defaults config' do
7
+ Prompt.new.config.should eq({padding: true, question: true})
8
+ end
9
+
10
+ it 'allows config' do
11
+ params = {padding: false, question: false}
12
+ Prompt.new(params).config.should eq(params)
13
+ end
14
+
15
+ it 'executes a block' do
16
+ prompt = Prompt.new do |p|
17
+ attrs.each do |attr|
18
+ p.send("#{attr.to_sym}=", "My #{attr}")
19
+ end
20
+ end
21
+ attrs.each do |attr|
22
+ prompt.send(attr.to_sym).should eq("My #{attr}")
23
+ end
24
+ end
25
+ end
26
+
27
+ context '#lines' do
28
+ it 'returns an array' do
29
+ prompt = Prompt.new{|p| p.title = 'My title'}
30
+ prompt.lines.should be_a_kind_of(Array)
31
+ end
32
+
33
+ it 'accepts a dsl' do
34
+ prompt = Prompt.new do |p|
35
+ attrs.each do |attr|
36
+ p.send("#{attr.to_sym}=", "My #{attr}")
37
+ end
38
+ end
39
+
40
+ prompt.lines.each_with_index do |line, i|
41
+ line.should include("My #{attrs[i]}")
42
+ end
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,17 @@
1
+ ENV['env'] = 'test'
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'chaperone'
7
+ require 'mocha/api'
8
+
9
+ RSpec.configure do |config|
10
+ include Mocha::API
11
+ include Chaperone
12
+
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.run_all_when_everything_filtered = true
15
+ config.filter_run :focus
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chaperone
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matthew Werner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: simplecov
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: mocha
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '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: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: thor
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: cocaine
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
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: activesupport
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
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
+ - !ruby/object:Gem::Dependency
111
+ name: highline
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Guides you step by step through the things you can mess up
127
+ email:
128
+ - mwerner@zendesk.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - .rspec
135
+ - Gemfile
136
+ - LICENSE.txt
137
+ - README.md
138
+ - Rakefile
139
+ - chaperone.gemspec
140
+ - examples/deploy.rb
141
+ - lib/chaperone.rb
142
+ - lib/chaperone/guide.rb
143
+ - lib/chaperone/prompt.rb
144
+ - lib/chaperone/version.rb
145
+ - spec/models/guide_spec.rb
146
+ - spec/models/prompt_spec.rb
147
+ - spec/spec_helper.rb
148
+ homepage: https://github.com/mwerner/chaperone
149
+ licenses:
150
+ - MIT
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ segments:
162
+ - 0
163
+ hash: -1260887828363319748
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ none: false
166
+ requirements:
167
+ - - ! '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ segments:
171
+ - 0
172
+ hash: -1260887828363319748
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 1.8.24
176
+ signing_key:
177
+ specification_version: 3
178
+ summary: Guides you step by step through the things you can mess up
179
+ test_files:
180
+ - spec/models/guide_spec.rb
181
+ - spec/models/prompt_spec.rb
182
+ - spec/spec_helper.rb