my 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+