my 0.3.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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Kevin W. Gisi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,26 @@
1
+ LICENSE
2
+ README.rdoc
3
+ Rakefile
4
+ VERSION
5
+ bin/my
6
+ features/advanced.feature
7
+ features/aliases.feature
8
+ features/files.feature
9
+ features/folder.feature
10
+ features/questions.feature
11
+ features/sinatra.feature
12
+ features/support/env.rb
13
+ features/support/hooks.rb
14
+ features/support/interactive_steps.rb
15
+ features/support/steps.rb
16
+ features/usage.feature
17
+ lib/my.rb
18
+ lib/my/config.rb
19
+ lib/my/runner.rb
20
+ lib/my/script.rb
21
+ spec/config_spec.rb
22
+ spec/runner_spec.rb
23
+ spec/script_spec.rb
24
+ spec/spec.opts
25
+ spec/spec_helper.rb
26
+ Manifest
data/README.rdoc ADDED
@@ -0,0 +1,37 @@
1
+ = My
2
+
3
+ My is a configuration and template manager written in Ruby, designed to provide a DSL for managing file and folder dependencies.
4
+
5
+ == Installation and Usage
6
+
7
+ In order to use My, simply install the gem:
8
+
9
+ gem install my
10
+
11
+ Then to run a My script, just run:
12
+
13
+ my [FILE|URL]
14
+
15
+ == My Scripts
16
+
17
+ My uses a Ruby script syntax to specify actions, like in the following example script:
18
+
19
+ # Sinatra My Script
20
+
21
+ file "app.rb" => "http://pastie.org/944315.txt"
22
+ file "config.ru" => "http://pastie.org/994640.txt"
23
+
24
+ ask "Will you be using external views?"
25
+ yes do
26
+ folder "views"
27
+ file "views/index.html" => "http://pastie.org/944311.txt"
28
+ end
29
+
30
+ ask "Will you be using an external stylesheet?"
31
+ yes do
32
+ folder "views"
33
+ file "views/style.sass" => "http://pastie.org/944313.txt"
34
+ end
35
+
36
+ == Copyright
37
+ Copyright (c) 2010 Kevin W. Gisi. Released under the MIT License
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'echoe'
2
+ require 'rake/rdoctask'
3
+ require 'cucumber/rake/task'
4
+ require 'spec/rake/spectask'
5
+
6
+ Echoe.new "my", File.read("VERSION").chomp do |m|
7
+ m.author = "Kevin W. Gisi"
8
+ m.email = "kevin@kevingisi.com"
9
+ m.summary = "Ruby template and configuration manager"
10
+ m.url = "http://gisikw.github.com/my"
11
+ m.development_dependencies << "cucumber >=0.7.2"
12
+ m.development_dependencies << "aruba >=0.1.9"
13
+ m.development_dependencies << "rspec >=1.3.0"
14
+ end
15
+
16
+ Spec::Rake::SpecTask.new(:spec) do |spec|
17
+ spec.libs << 'lib' << 'spec'
18
+ spec.spec_files = FileList['spec/**/*_spec.rb']
19
+ end
20
+
21
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
22
+ spec.libs << 'lib' << 'spec'
23
+ spec.spec_files = FileList['spec/**/*_spec.rb']
24
+ spec.rcov = true
25
+ spec.rcov_opts = ["-T"]
26
+ end
27
+
28
+ Cucumber::Rake::Task.new do |t|
29
+ t.cucumber_opts = %w{--format pretty}
30
+ end
31
+
32
+ Rake::RDocTask.new do |rdoc|
33
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
34
+ rdoc.rdoc_dir = 'rdoc'
35
+ rdoc.title = "My #{version}"
36
+ rdoc.main = 'README.rdoc'
37
+ rdoc.rdoc_files.include('README.rdoc')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end
40
+
41
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
data/bin/my ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__),'..','lib','my.rb')
4
+
5
+ My::Runner.execute(ARGV[0],ARGV[1..-1])
@@ -0,0 +1,29 @@
1
+ Feature: Advanced scripting
2
+
3
+ As a My script writer
4
+ I want to nest tasks inside of questions
5
+ So I can respond dynamically to the user's needs
6
+
7
+ Scenario: Nesting questions
8
+ Given a file named "yes.template" with:
9
+ """
10
+ The user picked yes
11
+ """
12
+ And a file named "script.rb" with:
13
+ """
14
+ ask "Are you sure you would like to apply this script?"
15
+ yes do
16
+ folder "foo"
17
+ file "foo.txt" => "yes.template"
18
+ ask "Would you like to create bar.txt?"
19
+ yes do
20
+ file "bar.txt" => "yes.template"
21
+ end
22
+ end
23
+ """
24
+ When I run "../../bin/my script.rb" interactively
25
+ And I type "y"
26
+ And I type "y"
27
+ And the program completes
28
+ Then the file "foo.txt" should contain "The user picked yes"
29
+ Then the file "bar.txt" should contain "The user picked yes"
@@ -0,0 +1,20 @@
1
+ Feature: Script aliases
2
+
3
+ As a user of the My gem
4
+ I want to register shortname for scripts
5
+ So I can save time
6
+
7
+ Scenario: Adding an alias
8
+ Given there are no scripts installed
9
+ And I run "../../bin/my add sinatra"
10
+ Then I should see "The sinatra script has been registered"
11
+
12
+ Scenario: Removing an alias
13
+ Given there is a "sinatra" script installed
14
+ And I run "../../bin/my rm sinatra"
15
+ Then I should see "The sinatra script has been removed"
16
+
17
+ Scenario: Listing aliases
18
+ Given there is a "sinatra" script installed
19
+ And I run "../../bin/my help"
20
+ Then I should see "sinatra"
@@ -0,0 +1,37 @@
1
+ Feature: File commands with My scripts
2
+
3
+ As a user of the My gem
4
+ I want to specify files in scripts
5
+ So that I can download them automatically
6
+
7
+ Scenario: Requiring files
8
+ Given a file named "test.txt.template" with:
9
+ """
10
+ My script test content
11
+ """
12
+ And a file named "test2.txt.template" with:
13
+ """
14
+ My script test2 content
15
+ """
16
+ And a file named "script.rb" with:
17
+ """
18
+ file "test.txt" => "test.txt.template"
19
+ file "test2.txt" => "test2.txt.template"
20
+ """
21
+ When I run "../../bin/my script.rb"
22
+ Then the file "test.txt" should contain "My script test content"
23
+ And the file "test2.txt" should contain "My script test2 content"
24
+
25
+ Scenario: Requiring a file with template options
26
+ Given a file named "test.txt.template" with:
27
+ """
28
+ My script injected content: <%= @content %>
29
+ """
30
+ And a file named "script.rb" with:
31
+ """
32
+ file "test.txt" => "test.txt.template" do
33
+ @content = "injection"
34
+ end
35
+ """
36
+ When I run "../../bin/my script.rb"
37
+ Then the file "test.txt" should contain "My script injected content: injection"
@@ -0,0 +1,13 @@
1
+ Feature: Folder commands with My scripts
2
+
3
+ As a user of the My gem
4
+ I want to specify folders in create
5
+ So that I can create them automatically
6
+
7
+ Scenario: Requiring a folder
8
+ Given a file named "script.rb" with:
9
+ """
10
+ folder "foo"
11
+ """
12
+ When I run "../../bin/my script.rb"
13
+ Then the "foo" directory should exist
@@ -0,0 +1,43 @@
1
+ Feature: Prompt the user for information with My scripts
2
+
3
+ As a user of the My gem
4
+ I want to optionally run tasks
5
+ So that I can be explicit
6
+
7
+ Scenario: Accepting a prompt
8
+ Given a file named "yes.txt.template" with:
9
+ """
10
+ The user picked yes
11
+ """
12
+ And a file named "script.rb" with:
13
+ """
14
+ ask "Would you like to add a file?"
15
+ yes do
16
+ file "yes.txt" => "yes.txt.template"
17
+ end
18
+ """
19
+ When I run "../../bin/my script.rb" interactively
20
+ Then the program should prompt "Would you like to add a file? [y/N]"
21
+
22
+ When I type "y"
23
+ And the program completes
24
+ Then the file "yes.txt" should contain "The user picked yes"
25
+
26
+ Scenario: Declining a prompt
27
+ Given a file named "no.txt.template" with:
28
+ """
29
+ The user picked no
30
+ """
31
+ And a file named "script.rb" with:
32
+ """
33
+ ask "Would you like to add a file?"
34
+ no do
35
+ file "no.txt" => "no.txt.template"
36
+ end
37
+ """
38
+ When I run "../../bin/my script.rb" interactively
39
+ Then the program should prompt "Would you like to add a file? [y/N]"
40
+
41
+ When I type "n"
42
+ And the program completes
43
+ Then the file "no.txt" should contain "The user picked no"
@@ -0,0 +1,72 @@
1
+ Feature: Ensuring README examples
2
+
3
+ As a My project maintainer
4
+ I want to ensure my Sinatra example works
5
+ So I that I avoid humiliation
6
+
7
+ Background:
8
+ Given a file named "script.rb" with:
9
+ """
10
+ # Sinatra My Script
11
+
12
+ file "app.rb" => "http://pastie.org/944315.txt"
13
+ file "config.ru" => "http://pastie.org/994640.txt"
14
+
15
+ ask "Will you be using external views?"
16
+ yes do
17
+ folder "views"
18
+ file "views/index.html" => "http://pastie.org/944311.txt"
19
+ end
20
+
21
+ ask "Will you be using an external stylesheet?"
22
+ yes do
23
+ folder "views"
24
+ file "views/style.sass" => "http://pastie.org/944313.txt"
25
+ end
26
+ """
27
+
28
+ Scenario: Answering yes and yes
29
+ When I run "../../bin/my script.rb" interactively
30
+ And I type "y"
31
+ And I type "y"
32
+ And the program completes
33
+ Then the following files should exist:
34
+ | app.rb |
35
+ | config.ru |
36
+ | views/index.html |
37
+ | views/style.sass |
38
+
39
+ Scenario: Answering yes and no
40
+ When I run "../../bin/my script.rb" interactively
41
+ And I type "y"
42
+ And I type "n"
43
+ And the program completes
44
+ Then the following files should exist:
45
+ | app.rb |
46
+ | config.ru |
47
+ | views/index.html |
48
+ And the following files should not exist:
49
+ | views/style.sass |
50
+
51
+ Scenario: Answering no and yes
52
+ When I run "../../bin/my script.rb" interactively
53
+ And I type "n"
54
+ And I type "y"
55
+ And the program completes
56
+ Then the following files should exist:
57
+ | app.rb |
58
+ | config.ru |
59
+ | views/style.sass |
60
+ And the following files should not exist:
61
+ | views/index.html |
62
+
63
+ Scenario: Answering no and no
64
+ When I run "../../bin/my script.rb" interactively
65
+ And I type "n"
66
+ And I type "n"
67
+ And the program completes
68
+ Then the following files should exist:
69
+ | app.rb |
70
+ | config.ru |
71
+ And the following folders should not exist:
72
+ | views |
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.dirname(__FILE__)+'/../../lib')
2
+ require 'aruba'
3
+ require 'my'
4
+
5
+ begin
6
+ require 'rspec/expectations'
7
+ rescue LoadError
8
+ require 'spec/expectations'
9
+ end
@@ -0,0 +1,8 @@
1
+ Before do
2
+ FileUtils.mv("~/.my_scripts","~/.my_scripts_backup") if File.exist? "~/.my_scripts"
3
+ File.open(File.expand_path("~/.my_scripts"),"w"){|f|f.write({}.to_yaml)}
4
+ end
5
+
6
+ After do
7
+ FileUtils.mv("~/.my_scripts_backup","~/.my_scripts") if File.exist? "~/.my_scripts_backup"
8
+ end
@@ -0,0 +1,41 @@
1
+ require 'open3'
2
+
3
+ @interactive_history = []
4
+
5
+ def run_interactive_program
6
+ old_dir = Dir.pwd
7
+ Dir.chdir("tmp/aruba") unless Dir.pwd.split('/')[-1] == "aruba"
8
+ @stdin, @stdout, @stderr = Open3.popen3(@interactive_prog)
9
+ @interactive_history.each do |input|
10
+ @stdin.puts input
11
+ end
12
+ @output = ""
13
+ begin
14
+ loop do
15
+ Timeout::timeout(1) do
16
+ @output << @stdout.readpartial(1)
17
+ end
18
+ end
19
+ rescue Timeout::Error
20
+ rescue EOFError
21
+ end
22
+ Dir.chdir(old_dir)
23
+ end
24
+
25
+ When /^I run "([^\"]*)" interactively$/ do |arg1|
26
+ @interactive_prog = arg1
27
+ @interactive_history = []
28
+ end
29
+
30
+ Then /^the program should prompt "([^\"]*)"$/ do |arg1|
31
+ run_interactive_program
32
+ @output.should include(arg1)
33
+ end
34
+
35
+ When /^I type "([^\"]*)"/ do |arg1|
36
+ @interactive_history << arg1
37
+ end
38
+
39
+ When /^the program completes$/ do
40
+ run_interactive_program
41
+ end
@@ -0,0 +1,22 @@
1
+ Then /^I debug$/ do
2
+ end
3
+
4
+ Given /^there are no scripts installed$/ do
5
+ File.open(My::Config.scripts,"w"){|f|f.write({}.to_yaml)}
6
+ end
7
+
8
+ Given /^there is a "([^\"]*)" script installed$/ do |arg1|
9
+ scripts = {}
10
+ scripts[arg1] = {:url => "http://pastie.org/944311.txt"}
11
+ File.open(My::Config.scripts,"w"){|f|f.write(scripts.to_yaml)}
12
+ end
13
+
14
+ Then /^the "([^\"]*)" directory should exist$/ do |arg1|
15
+ File.directory?("tmp/aruba/#{arg1}").should be_true
16
+ end
17
+
18
+ Then /^the following folders should (not )?exist:$/ do |negation,table|
19
+ table.raw.flatten.each do |folder|
20
+ File.exist?(folder).should == !negation
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ Feature: Help
2
+ As a user of the My gem
3
+ I want to view the usage information
4
+ So I can use the gem effectively
5
+
6
+ Scenario: Viewing the usage information implicitly
7
+ Given there are no scripts installed
8
+ And I run "../../bin/my"
9
+ Then I should see "My"
10
+ And I should see "USAGE: my [NAME|URL]"
11
+ And I should see "Additional commands:"
12
+ And I should see "Registered scripts:"
13
+
14
+ Scenario: Viewing the usage information explicitly
15
+ Given there are no scripts installed
16
+ And I run "../../bin/my help"
17
+ Then I should see "My v."
18
+ And I should see "USAGE: my [NAME|URL]"
19
+ And I should see "Additional commands:"
20
+ And I should see "Registered scripts:"
data/lib/my.rb ADDED
@@ -0,0 +1,13 @@
1
+ $:.unshift(File.dirname(__FILE__)+'/../lib')
2
+
3
+ $stdin.sync = true
4
+ $stdout.sync = true
5
+
6
+ require 'yaml'
7
+ require 'erb'
8
+ require 'open-uri'
9
+ require 'fileutils'
10
+
11
+ require 'my/config'
12
+ require 'my/script'
13
+ require 'my/runner'
data/lib/my/config.rb ADDED
@@ -0,0 +1,39 @@
1
+ # Author:: Kevin W. Gisi (mailto:kevin@kevingisi.com)
2
+ # Copyright:: Copyright (c) 2010 Kevin W. Gisi
3
+ # License:: Distributed under the MIT License
4
+
5
+ module My
6
+ # My::Config is the wrapper around all configurable options
7
+ # within the My gem. It tracks the version of the My gem,
8
+ # the environment in which My has been run, and the
9
+ # location of the My script registry.
10
+ module Config
11
+ extend self
12
+
13
+ @version = File.read(File.dirname(__FILE__)+"/../../VERSION").chomp
14
+
15
+ attr_accessor :environment,:version
16
+
17
+ # Returns the location of the My script registry,
18
+ # depending on the current environment.
19
+ #
20
+ # My::Config.environment = 'production'
21
+ # My::Config.scripts
22
+ # # => "/home/gisikw/.my_scripts"
23
+ #
24
+ # My::Config.environment = 'test'
25
+ # My::Config.scripts
26
+ # # => "/home/gisikw/.rvm/gems/ruby-1.8.7-p249/gems/my-0.3.0/test.yml"
27
+ def scripts
28
+ case self.environment||='production'
29
+ when /^production$/
30
+ return File.expand_path("~/.my_scripts")
31
+ when /^test$/
32
+ return File.expand_path(File.join(File.dirname(__FILE__),'../../test.yml'))
33
+ when /^cucumber$/
34
+ return File.expand_path(File.join(File.dirname(__FILE__),'../../test.yml'))
35
+ end
36
+ end
37
+
38
+ end
39
+ end
data/lib/my/runner.rb ADDED
@@ -0,0 +1,120 @@
1
+ # Author:: Kevin W. Gisi (mailto:kevin@kevingisi.com)
2
+ # Copyright:: Copyright (c) 2010 Kevin W. Gisi
3
+ # License:: Distributed under the MIT License
4
+
5
+ module My
6
+ # The My::Runner module is called directly whenever the My binary is run.
7
+ # It handles basic tasks like adding and removing script aliases
8
+ # and delegating what gets run.
9
+ module Runner
10
+ extend self
11
+
12
+ # Registers an alias to a script URL or file path, specified
13
+ # by <em>args[0]</em> as an alias name, and <em>args[1]</em>
14
+ # as a path.
15
+ #
16
+ # My::Runner.add(['google','http://www.google.com'])
17
+ def add(args)
18
+ scripts = YAML::load(File.read(My::Config.scripts))
19
+ unless scripts[args[0]]
20
+ scripts[args[0]] = {:url => args[1]}
21
+ File.open(My::Config.scripts,'w'){|f|f.write(scripts.to_yaml)}
22
+ puts "The #{args[0]} script has been registered"
23
+ else
24
+ puts "The #{args[0]} script is already registered. Please remove it first."
25
+ end
26
+ end
27
+
28
+ # Removes a registered script alias, specified by
29
+ # <em>args[0]</em> as the alias name.
30
+ #
31
+ # My::Runner.rm(['google'])
32
+ def rm(args)
33
+ scripts = YAML::load(File.read(My::Config.scripts))
34
+ if scripts[args[0]]
35
+ scripts.delete(args[0])
36
+ File.open(My::Config.scripts,'w'){|f|f.write(scripts.to_yaml)}
37
+ puts "The #{args[0]} script has been removed"
38
+ else
39
+ puts "No #{args[0]} script has been registered"
40
+ end
41
+ end
42
+
43
+ # Displays the My version information and basic usage
44
+ # information, along with a list of registered script
45
+ # aliases.
46
+ #
47
+ # My::Runner.help
48
+ #
49
+ # <em>produces (for example):</em>
50
+ #
51
+ # My v.0.3.0
52
+ # USAGE: my [NAME|URL]
53
+ #
54
+ # Additional commands:
55
+ # my add NAME URL # Add NAME as an alias to a script at URL
56
+ # my rm NAME # Remove the NAME alias
57
+ #
58
+ # Registered scripts:
59
+ # sinatra
60
+ # rails
61
+ # gem
62
+ def help
63
+ puts <<-END
64
+ My v.#{My::Config.version}
65
+ USAGE: my [NAME|URL]
66
+
67
+ Additional commands:
68
+ my add NAME URL # Add NAME as an alias to a script at URL
69
+ my rm NAME # Remove the NAME alias
70
+
71
+ Registered scripts:
72
+ END
73
+
74
+ YAML::load(File.read(My::Config.scripts)).each do |name,params|
75
+ puts "#{name.ljust(30)}#{params[:description]}"
76
+ end
77
+ end
78
+
79
+ # Runs an appropriate task based on the <em>command</em>
80
+ # argument passed. In order, execute will try to:
81
+ # * Run My::Runner#<em>command</em>
82
+ # * Run a registered script, whose alias is <em>command</em>
83
+ # * Run a script located at <em>command</em>
84
+ # * Run My::Runner#help
85
+ #
86
+ # My::Runner.execute('add',['google','http://www.google.com'])
87
+ # # Executes My::Runner.add(['google','http://www.google.com'])
88
+ #
89
+ # My::Runner.execute('google')
90
+ # # Executes a registered script named 'google'
91
+ #
92
+ # My::Runner.execute('http://www.google.com')
93
+ # # Executes a script located at 'http://www.google.com'
94
+ #
95
+ # My::Runner.execute('flibbitijibbet')
96
+ # # Executes My::Runner.help
97
+ def execute(command=nil,args=[])
98
+ if command
99
+ if respond_to?(command)
100
+ begin
101
+ self.send(command,args)
102
+ rescue
103
+ self.send(command)
104
+ end
105
+ elsif (scripts=YAML::load(File.read(My::Config.scripts))).keys.include?(command)
106
+ My::Script.new(open(scripts[command][:url]).read).run
107
+ else
108
+ begin
109
+ script = open(command)
110
+ rescue
111
+ help
112
+ end
113
+ My::Script.new(script.read).run if script
114
+ end
115
+ else
116
+ help
117
+ end
118
+ end
119
+ end
120
+ end
data/lib/my/script.rb ADDED
@@ -0,0 +1,177 @@
1
+ # Author:: Kevin W. Gisi (mailto:kevin@kevingisi.com)
2
+ # Copyright:: Copyright (c) 2010 Kevin W. Gisi
3
+ # License:: Distributed under the MIT License
4
+
5
+ module My
6
+ # The My::Script class acts as a wrapper around
7
+ # the My script DSL. A My::Script instance is created
8
+ # with a string or a Proc argument, which is instantly
9
+ # evaluated, converting the standard script syntax:
10
+ #
11
+ # file "app.rb" => "http://pastie.org/994577.txt"
12
+ # folder "views"
13
+ # folder "lib"
14
+ #
15
+ # To a My::Script instance with a registered queue of
16
+ # files and folders to be created when run.
17
+ class Script
18
+
19
+ # Creates a new Script and calls <code>instance_eval</code>
20
+ # on the <em>script</em> argument, either as a string or
21
+ # as a Proc.
22
+ #
23
+ # My::Script.new("file 'app.rb' => 'http://pastie.org/994577.txt'")
24
+ # # => #<My::Script:0x7fc5aef84398 @folders=[], @files=[{:proc=>nil, :to=>"app.rb", :from=>"http://pastie.org/994577.txt"}], @questions=[]>
25
+ #
26
+ # My::Script.new(Proc.new{file "app.rb" => "http://pastie.org/994577.txt"})
27
+ # # => #<My::Script:0x7fc5aef84398 @folders=[], @files=[{:proc=>nil, :to=>"app.rb", :from=>"http://pastie.org/994577.txt"}], @questions=[]>
28
+ def initialize(script)
29
+ @files = []
30
+ @folders = []
31
+ @questions = []
32
+ if script.class == Proc
33
+ instance_eval &script
34
+ else
35
+ instance_eval script
36
+ end
37
+ end
38
+
39
+ # Returns the binding for the Script object.
40
+ #
41
+ # s = My::Script.new('')
42
+ # s.get_binding
43
+ # # => #<Binding:0x7fc5aef7fc80>
44
+ def get_binding
45
+ return binding
46
+ end
47
+
48
+ # Registers a file to be created, using the first key in
49
+ # the <em>args</em> hash as the <code>:to</code> attribute
50
+ # and the first value as the <code>:from</code> attribute.
51
+ # Optionally, a block can be passed to specify a context
52
+ # for populating variables, if the file specified is an
53
+ # ERB-templated file.
54
+ #
55
+ # s = My::Script.new('')
56
+ # s.file("app.rb" => "http://pastie.org/994577.txt")
57
+ #
58
+ # s = My::Script.new('')
59
+ # s.file("app.rb" => "http://pastie.org/994577.txt") do
60
+ # @app_name = "AwesomeApp"
61
+ # end
62
+ def file(args,&block)
63
+ @files << {:from => args.values[0], :to => args.keys[0], :proc => block}
64
+ end
65
+
66
+ # Registers a folder to be created, using the <em>name</em>
67
+ # as the path to the folder.
68
+ #
69
+ # s = My::Script.new('')
70
+ # s.folder "views"
71
+ #
72
+ # s = My::Script.new('')
73
+ # s.folder "/home/gisikw/.vim"
74
+ def folder(name)
75
+ @folders << name
76
+ end
77
+
78
+ # Registers a new question, with the <em>query</em>
79
+ # parameter as the prompt for the user.
80
+ #
81
+ # s = My::Script.new('')
82
+ # s.ask("Would you like to use HAML instead of ERB?")
83
+ def ask(query)
84
+ @questions << {:query => query}
85
+ end
86
+
87
+ # Registers a Proc to be used with the most recent
88
+ # question, should the user respond affirmatively.
89
+ # The block passed in will be evaluated in the context
90
+ # of an empty script, and so can make use of any My::Script
91
+ # functionality.
92
+ #
93
+ # s = My::Script.new('')
94
+ # s.ask("Would you like to use HAML instead of ERB?")
95
+ # s.yes do
96
+ # file "views/index.haml" => "http://pastie.org/994577.txt"
97
+ # end
98
+ def yes(&block)
99
+ unless @questions.empty?
100
+ @questions.last[:yes] = block
101
+ end
102
+ end
103
+
104
+ # Registers a Proc to be used with the most recent
105
+ # question, should the user respond negatively.
106
+ # The block passed in will be evaluated in the context
107
+ # of an empty script, and so can make use of any My::Script
108
+ # functionality.
109
+ #
110
+ # s = My::Script.new('')
111
+ # s.ask("Would you like to use HAML instead of ERB?")
112
+ # s.no do
113
+ # file "views/index.erb" => "http://pastie.org/994577.txt"
114
+ # end
115
+ def no(&block)
116
+ unless @questions.empty?
117
+ @questions.last[:no] = block
118
+ end
119
+ end
120
+
121
+ # The run command does several tasks in executing the script
122
+ # in the following order:
123
+ # * Create all registered folders
124
+ # * Create all registered files, evaluating them with ERB if a block was passed
125
+ # * Ask all questions, spawning and executing a new script, using a Proc that corresponds to the user's answer.
126
+ #
127
+ # s = Script.new %Q{
128
+ # ask "Are you sure you would like to apply this script?"
129
+ # yes do
130
+ # file "app.rb" => "http://pastie.org/994577.txt"
131
+ # folder "lib"
132
+ # folder "views"
133
+ # ask "Would you like to use HAML instead of ERB?"
134
+ # yes do
135
+ # file => "views/index.haml" => "http://pastie.org/994577.txt"
136
+ # end
137
+ # no do
138
+ # file => "views/index.erb" => "http://pastie.org/994577.txt"
139
+ # end
140
+ # end
141
+ # }
142
+ # s.run
143
+ #
144
+ # <em>produces:</em>
145
+ #
146
+ # Are you sure you would like to apply this script? [y/N]
147
+ # # The user types "y\n"
148
+ # Would you like to use HAML instead of ERB?
149
+ # # The user types "n\n"
150
+ #
151
+ # # folders ["lib","views"] have been created
152
+ # # files ["app.rb","views/index.erb"] have been created
153
+ def run
154
+ @folders.each do |folder|
155
+ FileUtils.mkdir_p(folder)
156
+ end
157
+ @files.each do |file|
158
+ $stdout.puts "Writing file!"
159
+ FileUtils.mkdir_p(File.dirname(file[:to]))
160
+ if file[:proc]
161
+ open(file[:to],'w').write(ERB.new(open(file[:from]).read).result(My::Script.new(file[:proc]).get_binding))
162
+ else
163
+ open(file[:to],'w').write(open(file[:from]).read)
164
+ end
165
+ end
166
+ @questions.each do |question|
167
+ $stdout.print "#{question[:query]} [y/N] "
168
+ if $stdin.gets.chomp.downcase =~ /^y(?:es)?$/
169
+ My::Script.new(question[:yes]||Proc.new{}).run
170
+ else
171
+ My::Script.new(question[:no]||Proc.new{}).run
172
+ end
173
+ end
174
+ end
175
+
176
+ end
177
+ end
data/my.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{my}
5
+ s.version = "0.3.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Kevin W. Gisi"]
9
+ s.date = %q{2010-06-07}
10
+ s.default_executable = %q{my}
11
+ s.description = %q{Ruby template and configuration manager}
12
+ s.email = %q{kevin@kevingisi.com}
13
+ s.executables = ["my"]
14
+ s.extra_rdoc_files = ["LICENSE", "README.rdoc", "bin/my", "lib/my.rb", "lib/my/config.rb", "lib/my/runner.rb", "lib/my/script.rb"]
15
+ s.files = ["LICENSE", "README.rdoc", "Rakefile", "VERSION", "bin/my", "features/advanced.feature", "features/aliases.feature", "features/files.feature", "features/folder.feature", "features/questions.feature", "features/sinatra.feature", "features/support/env.rb", "features/support/hooks.rb", "features/support/interactive_steps.rb", "features/support/steps.rb", "features/usage.feature", "lib/my.rb", "lib/my/config.rb", "lib/my/runner.rb", "lib/my/script.rb", "spec/config_spec.rb", "spec/runner_spec.rb", "spec/script_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "Manifest", "my.gemspec"]
16
+ s.homepage = %q{http://gisikw.github.com/my}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "My", "--main", "README.rdoc"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{my}
20
+ s.rubygems_version = %q{1.3.6}
21
+ s.summary = %q{Ruby template and configuration manager}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<cucumber>, [">= 0.7.2"])
29
+ s.add_development_dependency(%q<aruba>, [">= 0.1.9"])
30
+ s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
31
+ else
32
+ s.add_dependency(%q<cucumber>, [">= 0.7.2"])
33
+ s.add_dependency(%q<aruba>, [">= 0.1.9"])
34
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<cucumber>, [">= 0.7.2"])
38
+ s.add_dependency(%q<aruba>, [">= 0.1.9"])
39
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe My::Config do
4
+ describe "scripts" do
5
+ describe "in the production environment" do
6
+ it "should return the .my_scripts file" do
7
+ My::Config.stubs(:environment).returns("production")
8
+ My::Config.scripts.should == File.expand_path("~/.my_scripts")
9
+ end
10
+ end
11
+ describe "in the test environment" do
12
+ it "should return the test.yml file" do
13
+ My::Config.stubs(:environment).returns("test")
14
+ My::Config.scripts.should == File.expand_path("test.yml")
15
+ end
16
+ end
17
+ describe "in the cucumber environment" do
18
+ it "should return the test.yml file" do
19
+ My::Config.stubs(:environment).returns("cucumber")
20
+ My::Config.scripts.should == File.expand_path("test.yml")
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "version" do
26
+ it "should return the version in the VERSION file" do
27
+ My::Config.version.should == File.read("VERSION").chomp
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,110 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe My::Runner do
4
+ describe "#add" do
5
+ describe "when the script name does not exist" do
6
+ it "adds an entry to the script registry" do
7
+ scripts = YAML::load(File.read(My::Config.scripts))
8
+ My::Runner.add(["google","http://google.com"])
9
+ (YAML::load(File.read(My::Config.scripts)).keys.size-scripts.keys.size).should == 1
10
+ end
11
+ it "informs the user the script has been registered" do
12
+ My::Runner.add(["google","http://google.com"])
13
+ @stdout.string.should =~ /The google script has been registered/
14
+ end
15
+ end
16
+ describe "when the script name does exist" do
17
+ before :each do
18
+ My::Runner.add(["google","http://google.com"])
19
+ end
20
+ it "does not overwrite the existing entry" do
21
+ scripts = File.read(My::Config.scripts)
22
+ My::Runner.add(["google","https://google.com"])
23
+ File.read(My::Config.scripts).should == scripts
24
+ end
25
+ it "prompts the user to remove the original script" do
26
+ My::Runner.add(["google","https://google.com"])
27
+ @stdout.string.should =~ /The google script is already registered\. Please remove it first\./
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#rm" do
33
+ describe "when the script has been registered" do
34
+ before :each do
35
+ My::Runner.add(["google","http://google.com"])
36
+ end
37
+ it "removes an entry from the script registry" do
38
+ scripts = YAML::load(File.read(My::Config.scripts))
39
+ scripts.size.should == 1
40
+ My::Runner.rm(["google"])
41
+ YAML::load(File.read(My::Config.scripts)).size.should == 0
42
+ (YAML::load(File.read(My::Config.scripts)).keys.size-scripts.keys.size).should == -1
43
+ end
44
+ end
45
+ describe "when the script has not been registered" do
46
+ it "does not modify the script registry" do
47
+ scripts = File.read(My::Config.scripts)
48
+ My::Runner.rm(["google"])
49
+ File.read(My::Config.scripts).should == scripts
50
+ end
51
+ it "informs the user no script exists" do
52
+ My::Runner.rm(["google"])
53
+ @stdout.string.should =~ /No google script has been registered/
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#help" do
59
+ it "parses the script registry" do
60
+ YAML.expects(:load).with(File.read(My::Config.scripts)).returns({})
61
+ My::Runner.help
62
+ end
63
+ end
64
+
65
+ describe "#execute" do
66
+ describe "when a command is passed" do
67
+ describe "and the method exists" do
68
+ it "runs the method" do
69
+ My::Runner.expects(:add)
70
+ My::Runner.execute "add"
71
+ end
72
+ end
73
+ describe "and the method does not exist" do
74
+ describe "and the command is a registered script name" do
75
+ it "runs the registered script" do
76
+ File.open("sample_script.rb","w"){|f|f.write("blah")}
77
+ My::Runner.add(["google","sample_script.rb"])
78
+ fake_script = My::Script.new ''
79
+ My::Script.expects(:new).with('blah').returns fake_script
80
+ My::Runner.execute "google"
81
+ FileUtils.rm_rf "sample_script.rb"
82
+ end
83
+ end
84
+ describe "and the command is not a registered script name" do
85
+ describe "and the command is a valid script location" do
86
+ it "creates a new script" do
87
+ File.open("temp_script.rb","w"){|f|f.write("blah")}
88
+ fake_script = My::Script.new ''
89
+ My::Script.expects(:new).returns(fake_script)
90
+ My::Runner.execute "temp_script.rb"
91
+ FileUtils.rm_rf "temp_script.rb"
92
+ end
93
+ end
94
+ describe "and the command is not a valid script location" do
95
+ it "calls the help method" do
96
+ My::Runner.expects(:help)
97
+ My::Runner.execute "feajhfaejf"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ describe "when no command is passed" do
104
+ it "calls the help method" do
105
+ My::Runner.expects(:help)
106
+ My::Runner.execute
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,149 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe My::Script do
4
+
5
+ describe "initializer" do
6
+
7
+ end
8
+
9
+ describe "#instance" do
10
+
11
+ before do
12
+ FileUtils.mkdir_p("tmp")
13
+ File.open("tmp/sample.template","w"){|f|f.write("This is a sample file")}
14
+ end
15
+
16
+ after do
17
+ FileUtils.rm_rf("tmp")
18
+ end
19
+
20
+ before :each do
21
+ @script = My::Script.new("")
22
+ end
23
+
24
+ describe "#file" do
25
+ it "adds to the list of files" do
26
+ count = @script.instance_eval("@files").size
27
+ @script.file("test.txt" => "tmp/sample.template")
28
+ @script.instance_eval("@files").size.should == count+1
29
+ end
30
+ end
31
+
32
+ describe "#folder" do
33
+ it "adds to the list of folders" do
34
+ count = @script.instance_eval("@folders").size
35
+ @script.folder("temp")
36
+ @script.instance_eval("@folders").size.should == count+1
37
+ end
38
+ end
39
+
40
+ describe "#ask" do
41
+ it "adds to the list of questions" do
42
+ count = @script.instance_eval("@questions").size
43
+ @script.ask("Do you want fries with that?")
44
+ @script.instance_eval("@questions").size.should == count+1
45
+ end
46
+ end
47
+
48
+ describe "#yes" do
49
+ describe "when a question has been added" do
50
+ before :each do
51
+ @script.ask("Do you want fries with that?")
52
+ end
53
+ it "attaches to the most recent question" do
54
+ @script.yes do
55
+ puts "hey"
56
+ end
57
+ @script.instance_eval("@questions").last[:yes].should_not be_nil
58
+ end
59
+ end
60
+ describe "when no question has been added" do
61
+ it "does not add to the questions" do
62
+ @script.yes do
63
+ puts "hey"
64
+ end
65
+ @script.instance_eval("@questions").should be_empty
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#no" do
71
+ describe "when a question has been added" do
72
+ before :each do
73
+ @script.ask("Do you want fries with that?")
74
+ end
75
+ it "attaches to the most recent question" do
76
+ @script.no do
77
+ puts "hey"
78
+ end
79
+ @script.instance_eval("@questions").last[:no].should_not be_nil
80
+ end
81
+ end
82
+ describe "when no question has been added" do
83
+ it "does not add to the questions" do
84
+ @script.no do
85
+ puts "hey"
86
+ end
87
+ @script.instance_eval("@questions").should be_empty
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#run" do
93
+
94
+ it "creates each folder in the folder list" do
95
+ @script.folder("temp_a")
96
+ @script.folder("temp_b")
97
+ @script.instance_eval("@folders").each do |folder|
98
+ FileUtils.expects(:mkdir_p).with(folder).at_least_once
99
+ end
100
+ @script.run
101
+ end
102
+
103
+ it "creates each file in the file list" do
104
+ @script.file "temp_a.txt" => "tmp/sample.template"
105
+ @script.file "temp_b.txt" => "tmp/sample.template"
106
+ @script.run
107
+ File.exist?("temp_a.txt").should be_true
108
+ File.exist?("temp_b.txt").should be_true
109
+ FileUtils.rm("temp_a.txt")
110
+ FileUtils.rm("temp_b.txt")
111
+ end
112
+
113
+ it "prompts the user for each question" do
114
+ @script.ask "Would you like fries with that?"
115
+ $stdin.expects(:gets).returns("y\n")
116
+ @script.run
117
+ @stdout.string.should =~ /Would you like fries with that\? \[y\/N\]/
118
+ end
119
+
120
+ describe "when the user answers yes to a question" do
121
+ it "should create a script from the yes block" do
122
+ @script.ask "Would you like fries with that?"
123
+ @script.yes do
124
+ puts "hey"
125
+ end
126
+ dummy_script = My::Script.new ''
127
+ My::Script.expects(:new).with(@script.instance_eval('@questions').first[:yes]).returns(dummy_script)
128
+ $stdin.expects(:gets).returns("y\n")
129
+ @script.run
130
+ end
131
+ end
132
+
133
+ describe "when the user answers no to a question" do
134
+ it "should create a script from the no block" do
135
+ @script.ask "Would you like fries with that?"
136
+ @script.no do
137
+ puts "hey"
138
+ end
139
+ dummy_script = My::Script.new ''
140
+ My::Script.expects(:new).with(@script.instance_eval('@questions').first[:no]).returns(dummy_script)
141
+ $stdin.expects(:gets).returns("n\n")
142
+ @script.run
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color --format nested
@@ -0,0 +1,27 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ require 'my'
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.mock_with :mocha
11
+ My::Config.environment = "test"
12
+ config.before :each do
13
+ File.open("test.yml","w"){|f|f.write({}.to_yaml)}
14
+ @orig_stdout = $stdout
15
+ @orig_stdin = $stdin
16
+ @stdin = StringIO.new
17
+ @stdout = StringIO.new
18
+ $stdin = @stdin
19
+ $stdout = @stdout
20
+ end
21
+ config.after :each do
22
+ FileUtils.rm_rf "test.yml"
23
+ $stdout = @orig_stdout
24
+ $stdin = @orig_stdin
25
+ end
26
+ end
27
+
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: my
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
10
+ platform: ruby
11
+ authors:
12
+ - Kevin W. Gisi
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-07 00:00:00 -05:00
18
+ default_executable: my
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: cucumber
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 7
30
+ - 2
31
+ version: 0.7.2
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: aruba
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 1
44
+ - 9
45
+ version: 0.1.9
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 1
57
+ - 3
58
+ - 0
59
+ version: 1.3.0
60
+ type: :development
61
+ version_requirements: *id003
62
+ description: Ruby template and configuration manager
63
+ email: kevin@kevingisi.com
64
+ executables:
65
+ - my
66
+ extensions: []
67
+
68
+ extra_rdoc_files:
69
+ - LICENSE
70
+ - README.rdoc
71
+ - bin/my
72
+ - lib/my.rb
73
+ - lib/my/config.rb
74
+ - lib/my/runner.rb
75
+ - lib/my/script.rb
76
+ files:
77
+ - LICENSE
78
+ - README.rdoc
79
+ - Rakefile
80
+ - VERSION
81
+ - bin/my
82
+ - features/advanced.feature
83
+ - features/aliases.feature
84
+ - features/files.feature
85
+ - features/folder.feature
86
+ - features/questions.feature
87
+ - features/sinatra.feature
88
+ - features/support/env.rb
89
+ - features/support/hooks.rb
90
+ - features/support/interactive_steps.rb
91
+ - features/support/steps.rb
92
+ - features/usage.feature
93
+ - lib/my.rb
94
+ - lib/my/config.rb
95
+ - lib/my/runner.rb
96
+ - lib/my/script.rb
97
+ - spec/config_spec.rb
98
+ - spec/runner_spec.rb
99
+ - spec/script_spec.rb
100
+ - spec/spec.opts
101
+ - spec/spec_helper.rb
102
+ - Manifest
103
+ - my.gemspec
104
+ has_rdoc: true
105
+ homepage: http://gisikw.github.com/my
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options:
110
+ - --line-numbers
111
+ - --inline-source
112
+ - --title
113
+ - My
114
+ - --main
115
+ - README.rdoc
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ segments:
130
+ - 1
131
+ - 2
132
+ version: "1.2"
133
+ requirements: []
134
+
135
+ rubyforge_project: my
136
+ rubygems_version: 1.3.6
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: Ruby template and configuration manager
140
+ test_files: []
141
+