taketo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem 'rspec'
5
+ gem 'rake'
6
+ gem 'aruba'
7
+ gem 'simplecov', :require => false
8
+ end
9
+
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ aruba (0.4.11)
5
+ childprocess (>= 0.2.3)
6
+ cucumber (>= 1.1.1)
7
+ ffi (>= 1.0.11)
8
+ rspec (>= 2.7.0)
9
+ builder (3.0.0)
10
+ childprocess (0.3.2)
11
+ ffi (~> 1.0.6)
12
+ cucumber (1.2.1)
13
+ builder (>= 2.1.2)
14
+ diff-lcs (>= 1.1.3)
15
+ gherkin (~> 2.11.0)
16
+ json (>= 1.4.6)
17
+ diff-lcs (1.1.3)
18
+ ffi (1.0.11)
19
+ gherkin (2.11.0)
20
+ json (>= 1.4.6)
21
+ json (1.7.3)
22
+ multi_json (1.3.6)
23
+ rake (0.9.2.2)
24
+ rspec (2.10.0)
25
+ rspec-core (~> 2.10.0)
26
+ rspec-expectations (~> 2.10.0)
27
+ rspec-mocks (~> 2.10.0)
28
+ rspec-core (2.10.1)
29
+ rspec-expectations (2.10.0)
30
+ diff-lcs (~> 1.1.3)
31
+ rspec-mocks (2.10.1)
32
+ simplecov (0.6.4)
33
+ multi_json (~> 1.0)
34
+ simplecov-html (~> 0.5.3)
35
+ simplecov-html (0.5.3)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ aruba
42
+ rake
43
+ rspec
44
+ simplecov
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Vladimir
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/README.md ADDED
@@ -0,0 +1,42 @@
1
+ Take Me To
2
+ ==========
3
+
4
+ [![Build Status](https://secure.travis-ci.org/v-yarotsky/taketo.png)](http://travis-ci.org/v-yarotsky/taketo)
5
+
6
+ A tiny helper utility to make access to servers eaiser for different projects and environments.
7
+
8
+ Usage:
9
+ ------
10
+
11
+ puts a config into ```~/.taketo.rc.rb```:
12
+
13
+ ```ruby
14
+ project :my_project do
15
+ environment :staging do
16
+ server :s1 do
17
+ host "1.2.3.4"
18
+ port 10001
19
+ user "app"
20
+ localtion "/var/app"
21
+ end
22
+ end
23
+ end
24
+ ```
25
+
26
+ Then execute:
27
+
28
+ ```taketo my_project staging s1 [command to execute, bash by default]```
29
+
30
+ To-Do:
31
+ ------
32
+
33
+ * Add support for defaults
34
+ * Add support for generating shortcuts
35
+
36
+ The Changelog:
37
+ --------------
38
+
39
+ ### v0.0.1 (13.06.2012) ###
40
+ * Initial release
41
+ * Support for simplest configs
42
+
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+
13
+ require 'rake'
14
+ require 'rake/testtask'
15
+ require 'cucumber'
16
+ require 'cucumber/rake/task'
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.test_files = Dir.glob('spec/**/*_spec.rb')
20
+ t.verbose = true
21
+ end
22
+
23
+ Cucumber::Rake::Task.new(:features) do |t|
24
+ t.cucumber_opts = "features --tags ~@wip --format pretty -x"
25
+ t.fork = false
26
+ end
27
+
28
+ task :default => [:test, :features]
29
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/taketo ADDED
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'taketo'
7
+ require 'taketo/constructs_factory'
8
+ require 'taketo/commands'
9
+ require 'optparse'
10
+ rescue LoadError => e #development
11
+ $: << File.expand_path('../../lib', __FILE__)
12
+ require 'bundler/setup'
13
+ retry
14
+ end
15
+
16
+ Signal.trap("SIGINT") do
17
+ puts "Terminating"
18
+ exit 1
19
+ end
20
+
21
+ include Taketo
22
+
23
+ def parse_options
24
+ options = { :config => File.join(ENV['HOME'], ".taketo.rc.rb") }
25
+
26
+ OptionParser.new do |opts|
27
+ opts.banner = <<-DESC
28
+ A tiny helper utility to make access to servers
29
+ eaiser for different projects and environments.
30
+ DESC
31
+
32
+ opts.on("-c CONFIG", "--config") do |c|
33
+ options[:config] = c
34
+ end
35
+
36
+ opts.on("--dry-run") do |v|
37
+ options[:dry_run] = v
38
+ end
39
+ end.parse!
40
+
41
+ options
42
+ end
43
+
44
+ def parse_config(options)
45
+ factory = Taketo::ConstructsFactory.new
46
+
47
+ Taketo::DSL.new(factory).configure do
48
+ config_text = File.read(options[:config])
49
+ eval config_text, binding, options[:config], 1
50
+ end
51
+ end
52
+
53
+ options = parse_options
54
+ config = parse_config(options)
55
+
56
+ project, environment, server = ARGV.shift(3).map(&:to_sym)
57
+
58
+ server = begin
59
+ config.projects.fetch(project).environments.fetch(environment).servers.fetch(server)
60
+ rescue KeyError => e
61
+ raise ArgumentError, e
62
+ end
63
+
64
+ remote_command = ARGV.join(" ")
65
+ remote_command = "bash" if remote_command.empty?
66
+ command_to_execute = Commands::SSHCommand.new(server).render(remote_command)
67
+ if options[:dry_run]
68
+ puts command_to_execute
69
+ else
70
+ system command_to_execute
71
+ end
72
+
@@ -0,0 +1,25 @@
1
+ Feature:
2
+ In order to be able to access my servers quickly
3
+ As a developer
4
+ I want to have a nifty little utility
5
+ configurable with simple DSL
6
+
7
+ Scenario: SSH to server
8
+ When I have the following config in "/tmp/taketo_test_cfg.rb"
9
+ """
10
+ project :slots do
11
+ environment :staging do
12
+ server :s1 do
13
+ host "1.2.3.4"
14
+ user "deployer"
15
+ location "/var/apps/slots"
16
+ end
17
+ end
18
+ end
19
+
20
+ """
21
+ And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run slots staging s1`
22
+ Then the output should contain
23
+ """
24
+ ssh -t "deployer"@"1.2.3.4" "cd '/var/apps/slots'; RAILS_ENV=staging bash"
25
+ """
@@ -0,0 +1,10 @@
1
+ When /^I have the following config in "(.*?)"$/ do |path, config|
2
+ @config_path = path
3
+ File.open(path, "w") do |f|
4
+ f.write(config)
5
+ end
6
+ end
7
+
8
+ Then /^the output should contain$/ do |expected|
9
+ assert_partial_output(expected, all_output)
10
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'aruba/cucumber'
4
+ require 'fileutils'
5
+
6
+ ENV['PATH'] = "#{File.expand_path('../../../bin', __FILE__)}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
7
+
8
+ After do
9
+ if defined? @config_path and File.exist?(@config_path)
10
+ FileUtils.rm(@config_path)
11
+ end
12
+ end
@@ -0,0 +1,44 @@
1
+ require 'forwardable'
2
+
3
+ module Taketo
4
+ module Commands
5
+ class SSHCommand
6
+ extend Forwardable
7
+
8
+ def_delegators :@server, :host, :port, :username, :default_location
9
+
10
+ def initialize(server, options = {})
11
+ @server = server
12
+ @environment = @server.environment
13
+ end
14
+
15
+ def render(command = "bash")
16
+ %Q[ssh -t #{port} #{username}#{host} "#{[location, environment, command].compact.join(" ")}"].gsub(/ +/, " ")
17
+ end
18
+
19
+ def host
20
+ unless @server.host
21
+ raise ArgumentError, "host for server #{@server.name} in #{@environment.name} is not defined!"
22
+ end
23
+ %Q["#{@server.host}"]
24
+ end
25
+
26
+ def port
27
+ %Q[-p #{@server.port}] if @server.port
28
+ end
29
+
30
+ def username
31
+ %Q["#{@server.username}"@] if @server.username
32
+ end
33
+
34
+ def location
35
+ %Q[cd '#{@server.default_location}';] if @server.default_location
36
+ end
37
+
38
+ def environment
39
+ %Q[RAILS_ENV=#{@environment.name}]
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,6 @@
1
+ module Taketo
2
+ module Commands
3
+ end
4
+ end
5
+
6
+ Dir.glob(File.expand_path('../commands/*.rb', __FILE__)).each { |c| require c }
@@ -0,0 +1,16 @@
1
+ module Taketo
2
+ module Constructs
3
+ class Config
4
+ attr_reader :projects
5
+
6
+ def initialize
7
+ @projects = {}
8
+ end
9
+
10
+ def append_project(project)
11
+ @projects[project.name] = project
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,18 @@
1
+ module Taketo
2
+ module Constructs
3
+ class Environment
4
+ attr_reader :name, :servers
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @servers = {}
9
+ end
10
+
11
+ def append_server(server)
12
+ server.environment = self
13
+ @servers[server.name] = server
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,17 @@
1
+ module Taketo
2
+ module Constructs
3
+ class Project
4
+ attr_reader :name, :environments
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @environments = {}
9
+ end
10
+
11
+ def append_environment(environment)
12
+ @environments[environment.name] = environment
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,13 @@
1
+ module Taketo
2
+ module Constructs
3
+ class Server
4
+ attr_reader :name
5
+ attr_accessor :host, :port, :username, :default_location, :environment
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,6 @@
1
+ module Taketo
2
+ module Constructs
3
+ end
4
+ end
5
+
6
+ Dir.glob(File.expand_path('../constructs/*.rb', __FILE__)).each { |c| require c }
@@ -0,0 +1,22 @@
1
+ require 'taketo/constructs'
2
+
3
+ module Taketo
4
+ class ConstructsFactory
5
+ def create_config
6
+ Constructs::Config.new
7
+ end
8
+
9
+ def create_project(*args)
10
+ Constructs::Project.new(*args)
11
+ end
12
+
13
+ def create_environment(*args)
14
+ Constructs::Environment.new(*args)
15
+ end
16
+
17
+ def create_server(*args)
18
+ Constructs::Server.new(*args)
19
+ end
20
+ end
21
+ end
22
+
data/lib/taketo/dsl.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'taketo/support'
2
+
3
+ module Taketo
4
+ class DSL
5
+ class ScopeError < StandardError; end
6
+
7
+ class << self
8
+ def define_scope(scope, parent_scope)
9
+ define_method scope do |name, &block|
10
+ unless current_scope?(parent_scope)
11
+ raise ScopeError,
12
+ "#{scope} can't be defined in #{current_scope} scope"
13
+ end
14
+ scope_object = @factory.send("create_#{scope}", name)
15
+ in_scope(scope, scope_object) do
16
+ block.call
17
+ end
18
+ end
19
+ end
20
+
21
+ def define_attribute(name, parent_scope, &block)
22
+ define_method name do |attribute|
23
+ unless server_scope?
24
+ raise ScopeError,
25
+ "#{name} can't be defined in #{current_scope} scope"
26
+ end
27
+ instance_exec(attribute, &block)
28
+ end
29
+ end
30
+ end
31
+
32
+ attr_reader :current_scope_object, :config
33
+
34
+ def initialize(factory)
35
+ @factory = factory
36
+ @scope = [:config]
37
+ @config = @current_scope_object = factory.create_config
38
+ end
39
+
40
+ def configure(&block)
41
+ instance_eval(&block)
42
+ @config
43
+ end
44
+
45
+ define_scope :project, :config
46
+ define_scope :environment, :project
47
+ define_scope :server, :environment
48
+
49
+ define_attribute :host, :server do |hostname|
50
+ current_scope_object.host = hostname
51
+ end
52
+
53
+ define_attribute :port, :server do |port_number|
54
+ current_scope_object.port = port_number
55
+ end
56
+
57
+ define_attribute :user, :server do |username|
58
+ current_scope_object.username = username
59
+ end
60
+
61
+ define_attribute :location, :server do |path|
62
+ current_scope_object.default_location = path
63
+ end
64
+
65
+ private
66
+
67
+ def current_scope
68
+ @scope.last
69
+ end
70
+
71
+ def current_scope?(scope)
72
+ current_scope == scope
73
+ end
74
+
75
+ [:config, :project, :environment, :server].each do |scope|
76
+ define_method("#{scope}_scope?") { current_scope == scope }
77
+ end
78
+
79
+ def in_scope(scope, new_scope_object)
80
+ parent_scope_object, @current_scope_object = @current_scope_object, new_scope_object
81
+ @scope << scope
82
+ yield
83
+ parent_scope_object.send("append_#{scope}", current_scope_object)
84
+ @scope.pop
85
+ @current_scope_object = parent_scope_object
86
+ end
87
+
88
+ end
89
+ end
90
+
@@ -0,0 +1,25 @@
1
+ module Taketo
2
+ module Support
3
+
4
+ ##
5
+ # This module allows to use external
6
+ # methods in block used by instance_eval,
7
+ # that it effectively mimics real closure
8
+ #
9
+ module EvalDelegator
10
+ def evaluate(&block)
11
+ @external_self = eval "self", block.binding
12
+ self.instance_eval(&block)
13
+ end
14
+
15
+ def method_missing(method_name, *args, &block)
16
+ if @external_self.respond_to?(method_name)
17
+ @external_self.send(method_name, *args, &block)
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,7 @@
1
+ module Taketo
2
+ module Support
3
+ end
4
+ end
5
+
6
+ require 'taketo/support/eval_delegator'
7
+
data/lib/taketo.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Taketo
2
+ version_file = File.expand_path('../VERSION', File.dirname(__FILE__))
3
+ VERSION = File.read(version_file).freeze
4
+ end
5
+
6
+ require 'taketo/support'
7
+ require 'taketo/dsl'
8
+ require 'taketo/commands'
9
+
@@ -0,0 +1,48 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+ require 'taketo/dsl'
3
+
4
+ describe "Taketo DSL" do
5
+ it "should parse config and instantiate objects" do
6
+ factory = Taketo::ConstructsFactory.new
7
+ config = Taketo::DSL.new(factory).configure do
8
+ project :slots do
9
+ environment :staging do
10
+ server :staging do
11
+ host "127.0.0.2"
12
+ user "deployer"
13
+ location "/var/app"
14
+ end
15
+ end
16
+
17
+ environment :production do
18
+ {
19
+ :s1 => "127.0.0.3",
20
+ :s2 => "127.0.0.4",
21
+ }.each do |server_name, host_name|
22
+ server server_name do
23
+ host host_name
24
+ location "/var/app"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ config.projects.length.should == 1
32
+ project = config.projects[:slots]
33
+ project.name.should == :slots
34
+
35
+ project.environments.length.should == 2
36
+ staging = project.environments[:staging]
37
+
38
+ staging.servers.length.should == 1
39
+ staging_server = staging.servers[:staging]
40
+ staging_server.host.should == "127.0.0.2"
41
+ staging_server.username.should == "deployer"
42
+ staging_server.default_location.should == "/var/app"
43
+
44
+ production = project.environments[:production]
45
+ production.servers.length.should == 2
46
+ end
47
+ end
48
+
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require 'taketo/commands/ssh_command'
3
+
4
+ include Taketo::Commands
5
+
6
+ describe "SSH Command" do
7
+ let(:environment) { stub(:Environment, :name => :staging) }
8
+ let(:server) do
9
+ stub(:Server, :name => :s1,
10
+ :host => "1.2.3.4",
11
+ :port => 22,
12
+ :username => "deployer",
13
+ :default_location => "/var/app",
14
+ :environment => environment)
15
+ end
16
+
17
+ let(:ssh_command) { SSHCommand.new(server) }
18
+
19
+ it "should compose command based on provided server object" do
20
+ ssh_command.render("bash").should == %q[ssh -t -p 22 "deployer"@"1.2.3.4" "cd '/var/app'; RAILS_ENV=staging bash"]
21
+ end
22
+
23
+ it "should ignore absent parts" do
24
+ server.stub(:port => nil)
25
+ server.stub(:username => nil)
26
+ ssh_command.render("bash").should == %q[ssh -t "1.2.3.4" "cd '/var/app'; RAILS_ENV=staging bash"]
27
+
28
+ server.stub(:default_location => nil)
29
+ ssh_command.render("bash").should == %q[ssh -t "1.2.3.4" "RAILS_ENV=staging bash"]
30
+ end
31
+
32
+ it "should require host" do
33
+ server.stub(:host => nil)
34
+ expect do
35
+ ssh_command.render("bash")
36
+ end.to raise_error ArgumentError, /host/
37
+ end
38
+
39
+ it "should have 'bash' as command default" do
40
+ ssh_command.render.should =~ /bash/
41
+ end
42
+ end
43
+
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require 'taketo/constructs/config'
3
+
4
+ include Taketo
5
+
6
+ describe "Config" do
7
+ let(:config) { Taketo::Constructs::Config.new }
8
+
9
+ describe "#append_project" do
10
+ it "should add project to config's projects collection" do
11
+ project = stub(:name => :foo)
12
+ config.append_project(project)
13
+ config.projects[:foo].should == project
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require 'taketo/constructs/environment'
3
+
4
+ include Taketo
5
+
6
+ describe "Environment" do
7
+ let(:environment) { Taketo::Constructs::Environment.new(:foo) }
8
+
9
+ it "should have name" do
10
+ environment.name.should == :foo
11
+ end
12
+
13
+ describe "#append_server" do
14
+ let(:server) { mock(:Server, :name => :foo).as_null_object }
15
+
16
+ it "should add a server to environment's servers collection" do
17
+ environment.append_server(server)
18
+ environment.servers[:foo].should == server
19
+ end
20
+
21
+ it "should set environment attribute on a server to self" do
22
+ server.should_receive(:environment=).with(environment)
23
+ environment.append_server(server)
24
+ end
25
+ end
26
+ end
27
+
28
+
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require 'taketo/constructs/project'
3
+
4
+ include Taketo
5
+
6
+ describe "Project" do
7
+ let(:project) { Taketo::Constructs::Project.new(:foo) }
8
+
9
+ it "should have name" do
10
+ project.name.should == :foo
11
+ end
12
+
13
+ describe "#append_environment" do
14
+ it "should add an environment to project's environments collection" do
15
+ environment = stub(:name => :foo)
16
+ project.append_environment(environment)
17
+ project.environments[:foo].should == environment
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,41 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require 'taketo/constructs/server'
3
+ require 'stringio'
4
+
5
+ include Taketo
6
+
7
+ describe "Server" do
8
+ let(:server) { Taketo::Constructs::Server.new(:foo) }
9
+
10
+ it "should have name" do
11
+ server.name.should == :foo
12
+ end
13
+
14
+ it "should set host" do
15
+ server.host = "foo"
16
+ server.host.should == "foo"
17
+ end
18
+
19
+ it "should set port" do
20
+ server.port = "foo"
21
+ server.port.should == "foo"
22
+ end
23
+
24
+ it "should set username" do
25
+ server.username = "foo"
26
+ server.username.should == "foo"
27
+ end
28
+
29
+ it "should set default_location" do
30
+ server.default_location = "foo"
31
+ server.default_location.should == "foo"
32
+ end
33
+
34
+ it "should set environment" do
35
+ environment = stub(:Environment)
36
+ server.environment = environment
37
+ server.environment.should == environment
38
+ end
39
+ end
40
+
41
+
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+ require 'taketo/constructs_factory'
3
+
4
+ include Taketo
5
+
6
+ describe "ConstructsFactory" do
7
+ let(:factory) { Taketo::ConstructsFactory.new }
8
+
9
+ specify "#create_config should create a config object" do
10
+ factory.create_config.should be_an_instance_of(Taketo::Constructs::Config)
11
+ end
12
+
13
+ specify "#create_project should create a project object" do
14
+ project = factory.create_project(:foo)
15
+ project.should be_an_instance_of(Taketo::Constructs::Project)
16
+ end
17
+
18
+ specify "#create_environment should create an environment object" do
19
+ environment = factory.create_environment(:foo)
20
+ environment.should be_an_instance_of(Taketo::Constructs::Environment)
21
+ end
22
+
23
+ specify "#create_server should create a server object" do
24
+ server = factory.create_server(:foo)
25
+ server.should be_an_instance_of(Taketo::Constructs::Server)
26
+ end
27
+ end
28
+
@@ -0,0 +1,108 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+ require 'support/helpers/dsl_spec_helper'
3
+ require 'taketo/dsl'
4
+
5
+ include Taketo
6
+
7
+ describe "DSL" do
8
+ extend DSLSpec
9
+ include DSLSpec
10
+
11
+ shared_examples "a scope" do |scope_name, parent_scope_name|
12
+ parent_scope = scopes[parent_scope_name]
13
+
14
+ it { should enclose_scope(scope_name).under(parent_scope) }
15
+ it { should be_appropriate_construct(scope_name, :foo).under(parent_scope) }
16
+
17
+ scopes.except(parent_scope_name).each do |inappropriate_scope|
18
+ it { should_not be_appropriate_construct(scope_name, :foo).under(inappropriate_scope) }
19
+ end
20
+
21
+ it "should create a #{scope_name} and set it as current scope object" do
22
+ factory.should_receive("create_#{scope_name}").with(:bar)
23
+ dsl(parent_scope, factory.send("create_#{parent_scope_name}")) do |c|
24
+ c.send(scope_name, :bar) do
25
+ c.current_scope_object.should == factory.send(scope_name)
26
+ end
27
+ end
28
+ end
29
+
30
+ it "should not leak #{scope_name} as current scope object" do
31
+ dsl(parent_scope, factory.send("create_#{parent_scope_name}")) do |c|
32
+ c.send(scope_name, :bar) {}
33
+ c.current_scope_object.should_not == factory.send(scope_name)
34
+ end
35
+ end
36
+
37
+ it "should add a #{scope_name} to the #{parent_scope_name}'s #{scope_name}s collection" do
38
+ dsl(parent_scope, factory.send("create_#{parent_scope_name}")) do |c|
39
+ c.current_scope_object.should_receive("append_#{scope_name}").with(factory.send("create_#{scope_name}", :bar))
40
+ c.send(scope_name, :bar) {}
41
+ end
42
+ end
43
+ end
44
+
45
+ shared_examples "an attribute" do |attribute_name, parent_scope_name, parent_scope_method, example_value|
46
+ parent_scope = scopes[parent_scope_name]
47
+
48
+ it { should be_appropriate_construct(attribute_name, example_value).under(parent_scope) }
49
+
50
+ scopes.except(parent_scope_name).each do |inaproppriate_scope|
51
+ it { should_not be_appropriate_construct(attribute_name, example_value).under(inaproppriate_scope) }
52
+ end
53
+
54
+ it "should set #{parent_scope_method.to_s.gsub('=', '')} attribute on current server" do
55
+ dsl(parent_scope, factory.send("create_#{parent_scope_name}", :foo)) do |c|
56
+ factory.send(parent_scope_name).should_receive(parent_scope_method).with(example_value)
57
+ c.send(attribute_name, example_value)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#project" do
63
+ it_behaves_like "a scope", :project, :config
64
+
65
+ describe "#environment" do
66
+ it_behaves_like "a scope", :environment, :project
67
+
68
+ describe "#server" do
69
+ it_behaves_like "a scope", :server, :environment
70
+
71
+ describe "#host" do
72
+ it_behaves_like "an attribute", :host, :server, :host=, "127.0.0.2"
73
+ end
74
+
75
+ describe "#port" do
76
+ it_behaves_like "an attribute", :port, :server, :port=, 4096
77
+ end
78
+
79
+ describe "#user" do
80
+ it_behaves_like "an attribute", :user, :server, :username=, "deployer"
81
+ end
82
+
83
+ describe "#location" do
84
+ it_behaves_like "an attribute", :location, :server, :default_location=, "/var/app/"
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "#current_scope_object" do
91
+ it "should be config initially" do
92
+ dsl do |c|
93
+ c.current_scope_object.should == factory.config
94
+ end
95
+ end
96
+
97
+ it "should correspond to current scope" do
98
+ dsl(:project, factory.create_project(:foo)) do |c|
99
+ c.current_scope_object.should == factory.project
100
+ end
101
+
102
+ dsl(:server, factory.create_server(:foo)) do |c|
103
+ c.current_scope_object.should == factory.server
104
+ end
105
+ end
106
+ end
107
+ end
108
+
@@ -0,0 +1,37 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require 'taketo/support/eval_delegator'
3
+
4
+ class EvalDelegatorContext
5
+ include Taketo::Support::EvalDelegator
6
+
7
+ def foo
8
+ end
9
+ end
10
+
11
+ describe Taketo::Support::EvalDelegator do
12
+ describe "#evaluate" do
13
+ it "should execute methods on context if it responds" do
14
+ expect do
15
+ EvalDelegatorContext.new.evaluate { foo }
16
+ end.not_to raise_error
17
+ end
18
+
19
+ it "should delegate unknown methods to calling context" do
20
+ class << self
21
+ define_method(:bar) {}
22
+ end
23
+
24
+ expect do
25
+ EvalDelegatorContext.new.evaluate { bar }
26
+ end.not_to raise_error
27
+ end
28
+
29
+ it "should pass local variables through the scopes" do
30
+ baz = :foo
31
+ expect do
32
+ EvalDelegatorContext.new.evaluate { baz }
33
+ end.not_to raise_error
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ if ENV['COVERAGE']
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+ end
8
+
9
+ $: << File.expand_path('../../lib', __FILE__)
10
+
11
+ require 'rspec'
12
+ require 'rspec/autorun'
13
+
14
+ require 'taketo/dsl'
15
+
16
+ Dir[File.dirname(__FILE__) + "/support/matchers/*.rb"].each {|f| require f}
17
+
@@ -0,0 +1,59 @@
1
+ module DSLSpec
2
+ class TestConstructsFactory
3
+ attr_reader :config, :project, :environment, :server
4
+
5
+ def create_config
6
+ @config ||= RSpec::Mocks::Mock.new(:Config).as_null_object
7
+ end
8
+
9
+ def create_project(name = :foo)
10
+ @project ||= RSpec::Mocks::Mock.new(:Project, :name => name).as_null_object
11
+ end
12
+
13
+ def create_environment(name = :foo)
14
+ @environment ||= RSpec::Mocks::Mock.new(:Environment, :name => name).as_null_object
15
+ end
16
+
17
+ def create_server(name = :foo)
18
+ @server ||= RSpec::Mocks::Mock.new(:Server, :name => name).as_null_object
19
+ end
20
+ end
21
+
22
+ def factory
23
+ @factory ||= TestConstructsFactory.new
24
+ end
25
+
26
+ RSpec.configure do |config|
27
+ config.after(:each) do
28
+ @factory = nil
29
+ end
30
+ end
31
+
32
+ def dsl(scope = [:config], scope_object = nil)
33
+ context = DSL.new(factory)
34
+
35
+ def context.set_scope(s, obj)
36
+ @scope = s
37
+ @current_scope_object = obj
38
+ end
39
+
40
+ context.set_scope(scope, scope_object || factory.create_config)
41
+
42
+ yield context
43
+ end
44
+
45
+ def scopes
46
+ scopes_hash = {
47
+ :config => [:config],
48
+ :project => [:config, :project],
49
+ :environment => [:config, :project, :environment],
50
+ :server => [:config, :project, :environment, :server]
51
+ }
52
+
53
+ def scopes_hash.except(*keys)
54
+ self.values_at(*(self.keys - keys))
55
+ end
56
+
57
+ scopes_hash
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ require 'taketo/dsl'
2
+
3
+ RSpec::Matchers.define :be_appropriate_construct do |construct, *args|
4
+ chain(:under) do |enclosing_scope|
5
+ @enclosing_scope = enclosing_scope
6
+ end
7
+
8
+ match do |actual|
9
+ unless @enclosing_scope
10
+ raise ArgumentError, "#under must be called to set enclosing scope"
11
+ end
12
+
13
+ @result = true
14
+ dsl(@enclosing_scope) do |c|
15
+ begin
16
+ c.send(construct, *args) {}
17
+ rescue Taketo::DSL::ScopeError => e
18
+ @result = false
19
+ rescue
20
+ #nothing
21
+ end
22
+ end
23
+ @result
24
+ end
25
+
26
+ description do
27
+ "#{name_to_sentence} ##{construct}(#{args.join(", ")}) under #{@enclosing_scope.inspect}"
28
+ end
29
+
30
+ failure_message_for_should do |actual|
31
+ "expected construct #{construct} to be appropriate under #{@enclosing_scope.inspect} scope"
32
+ end
33
+
34
+ failure_message_for_should_not do |actual|
35
+ "expected construct #{construct} not to be appropriate under #{@enclosing_scope.inspect} scope"
36
+ end
37
+ end
38
+
@@ -0,0 +1,18 @@
1
+ RSpec::Matchers.define :enclose_scope do |expected_scope|
2
+ chain(:under) do |scope|
3
+ @external_scope = scope
4
+ end
5
+
6
+ match do |actual|
7
+ @result = true
8
+ dsl(@external_scope || [:config]) do |c|
9
+ @result &= !c.send(:current_scope?, expected_scope)
10
+ c.send(expected_scope, :foo) do
11
+ @result &= c.send(:current_scope?, expected_scope)
12
+ end
13
+ @result &= !c.send(:current_scope?, expected_scope)
14
+ end
15
+ @result
16
+ end
17
+ end
18
+
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: taketo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vladimir Yarotsky
9
+ - Maksim Yermalovich
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-06-13 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '2.10'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '2.10'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rake
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '0.9'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '0.9'
47
+ - !ruby/object:Gem::Dependency
48
+ name: aruba
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.4'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '0.4'
63
+ - !ruby/object:Gem::Dependency
64
+ name: simplecov
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: '0.6'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: '0.6'
79
+ description:
80
+ email: vladimir.yarotksy@gmail.com
81
+ executables:
82
+ - taketo
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - bin/taketo
87
+ - lib/taketo/commands/ssh_command.rb
88
+ - lib/taketo/commands.rb
89
+ - lib/taketo/constructs/config.rb
90
+ - lib/taketo/constructs/environment.rb
91
+ - lib/taketo/constructs/project.rb
92
+ - lib/taketo/constructs/server.rb
93
+ - lib/taketo/constructs.rb
94
+ - lib/taketo/constructs_factory.rb
95
+ - lib/taketo/dsl.rb
96
+ - lib/taketo/support/eval_delegator.rb
97
+ - lib/taketo/support.rb
98
+ - lib/taketo.rb
99
+ - spec/integration/dsl_integration_spec.rb
100
+ - spec/lib/commands/ssh_command_spec.rb
101
+ - spec/lib/constructs/config_spec.rb
102
+ - spec/lib/constructs/environment_spec.rb
103
+ - spec/lib/constructs/project_spec.rb
104
+ - spec/lib/constructs/server_spec.rb
105
+ - spec/lib/constructs_factory_spec.rb
106
+ - spec/lib/dsl_spec.rb
107
+ - spec/lib/support/eval_delegator_spec.rb
108
+ - spec/spec_helper.rb
109
+ - spec/support/helpers/dsl_spec_helper.rb
110
+ - spec/support/matchers/be_appropriate_construct_matcher.rb
111
+ - spec/support/matchers/enclose_scope_matcher.rb
112
+ - features/connect_to_server.feature
113
+ - features/step_definitions/main_steps.rb
114
+ - features/support/env.rb
115
+ - Gemfile
116
+ - Gemfile.lock
117
+ - Rakefile
118
+ - LICENSE.txt
119
+ - README.md
120
+ - VERSION
121
+ homepage: http://github.com/v-yarotsky/taketo
122
+ licenses:
123
+ - MIT
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: 1.3.6
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 1.8.21
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: A tiny helper utility to make access to servers eaiser for different projects
146
+ and environments
147
+ test_files: []