duct 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f20e93081ed84a57df274ce99797d4aba409c43e
4
+ data.tar.gz: f075c2159472292ee1cb0f6cae1927b06cb2a8a8
5
+ SHA512:
6
+ metadata.gz: 0b8619568bf00163da213ee8bd4ea5480d582101b9dcc7916fb9a4cca4032126682f27488b23694f2897d274b8dd8a0710adea06ee9ae4c7616ec0c8740c4fc8
7
+ data.tar.gz: 76cde8fe434e75b2101bf13d92cc3a96d095141aeb08a6cd78017c6f09d56d5f7c6627660ef8f8810638a62df88d8f5d079f79c6b6c3f198e1ca80a8130aaa67
data/README.md CHANGED
@@ -1,24 +1,84 @@
1
1
  # Duct
2
2
 
3
- TODO: Write a gem description
3
+ ![Duct Tape, By Evan-Amos, via Wikimedia Commons](http://upload.wikimedia.org/wikipedia/commons/thumb/8/89/Duct-tape.jpg/256px-Duct-tape.jpg)
4
4
 
5
- ## Installation
5
+ Duct is a small wrapper around [bundler](http://bundler.io/). It allows you to embed a Gemfile in a script.
6
6
 
7
- Add this line to your application's Gemfile:
7
+ ## Usecase
8
8
 
9
- gem 'duct'
9
+ Sometimes you write small scripts to do different tasks. Sometimes you store them for future use. Sometimes those
10
+ scripts use some gems to do their task (database access, web requests, whatever). So, after some time, you reuse them
11
+ and you don't know which version of which gems did you use and you can run into trouble (like with full fledged apps in
12
+ the pre-bundler days). That's when you do the obvious workaround: create a directory to store the script together with a
13
+ `Gemfile` and a `Gemfile.lock`.
10
14
 
11
- And then execute:
15
+ That's a good solution but feels a bit overkill. Duct allows you to embed the `Gemfile` (and the `Gemfile.lock`) in the same file, so it's a single file to store together with others, as a [gist](https://gist.github.com/), etc.
12
16
 
13
- $ bundle
17
+ ## Installation
14
18
 
15
- Or install it yourself as:
19
+ Duct is a command line utility, so just install it via rubygems:
16
20
 
17
21
  $ gem install duct
18
22
 
19
23
  ## Usage
20
24
 
21
- TODO: Write usage instructions here
25
+ First, write your `Gemfile` in the data section of your script, after the `__END__` label, and after a `@@ Gemfile`
26
+ label:
27
+
28
+ ```ruby
29
+ require 'sinatra'
30
+
31
+ get '/' do
32
+ 'Hello, world!'
33
+ end
34
+
35
+ __END__
36
+ @@ Gemfile
37
+ source 'https://rubygems.org'
38
+
39
+ gem 'sinatra'
40
+ ```
41
+
42
+ (this is very much like the [Sinatra inline templates](http://www.sinatrarb.com/intro.html#Inline%20Templates), and can
43
+ in fact be combined with them).
44
+
45
+ Then, run the script using the `duct` command:
46
+
47
+ ```
48
+ $ duct my_script.rb
49
+ ```
50
+
51
+ The default action is running the script, checking previously whether dependencies are met, and installing them (via
52
+ `bundle install`) if needed. Notice that your script data section will be updated with a section for the `Gemfile.lock`
53
+ if needed (beware of conflicts with your editor while you develop the script).
54
+
55
+ ### Passing parameters
56
+
57
+ If your script expects parameters, just pass them after the filename:
58
+
59
+ ```
60
+ $ duct my_script.rb param1 param2
61
+ ```
62
+
63
+ ### Updating the bundle
64
+
65
+ You can run any of the `bundle` subcommands (mainly `update`, with or without a gem name, but also `outdated`, `check`,
66
+ `list`, `show` and [all the rest](http://bundler.io/v1.5/man/bundle.1.html#PRIMARY-COMMANDS)) passing them *before* the
67
+ filename:
68
+
69
+ ```
70
+ $ duct update sinatra my_script.rb
71
+ ```
72
+
73
+ Remember that updating the bundle will update the `Gemfile.lock` section in your script, so remember to save those
74
+ changes.
75
+
76
+ ### Using the script data
77
+
78
+ Duct will ignore the part of the data section **before** the first `@@ XYZ` label (and the sections with other labels
79
+ than `@@ Gemfile` and `@@ Gemfile.lock`, as it was mentioned for the Sinatra inline templates case), so you can still
80
+ use that ruby feature, but you will need to make sure your script handles and ignores the `Gemfile` and `Gemfile.lock`
81
+ sections, of course.
22
82
 
23
83
  ## Contributing
24
84
 
@@ -27,3 +87,7 @@ TODO: Write usage instructions here
27
87
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
88
  4. Push to the branch (`git push origin my-new-feature`)
29
89
  5. Create new Pull Request
90
+
91
+ ## License
92
+
93
+ Released under the MIT License, Copyright (c) 2014 Sergio Gil.
data/Rakefile CHANGED
@@ -1 +1,7 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/bin/duct ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'duct/cli'
7
+
8
+ Duct::Cli.new(ARGV.dup).run
data/duct.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Duct::VERSION
9
9
  spec.authors = ["Sergio Gil"]
10
10
  spec.email = ["sgilperez@gmail.com"]
11
- spec.description = %q{duct tape}
12
- spec.summary = %q{duct tape}
11
+ spec.description = %q{Embeds a Gemfile in a script}
12
+ spec.summary = %q{Embeds a Gemfile in a script}
13
13
  spec.homepage = "https://github.com/porras/duct"
14
14
  spec.license = "MIT"
15
15
 
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "bundler"
22
+
21
23
  spec.add_development_dependency "bundler", "~> 1.3"
22
24
  spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
23
26
  end
@@ -0,0 +1,32 @@
1
+ require 'sinatra'
2
+
3
+ get '/' do
4
+ @name = params[:name] || 'world'
5
+ erb :index
6
+ end
7
+
8
+ __END__
9
+ @@ Gemfile
10
+ source 'https://rubygems.org'
11
+
12
+ gem 'sinatra'
13
+ @@ Gemfile.lock
14
+ GEM
15
+ remote: https://rubygems.org/
16
+ specs:
17
+ rack (1.5.2)
18
+ rack-protection (1.5.1)
19
+ rack
20
+ sinatra (1.4.4)
21
+ rack (~> 1.4)
22
+ rack-protection (~> 1.4)
23
+ tilt (~> 1.3, >= 1.3.4)
24
+ tilt (1.4.1)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ sinatra
31
+ @@ index
32
+ Hello, <%= @name %>!
data/lib/duct.rb CHANGED
@@ -1,5 +1,3 @@
1
- require "duct/version"
2
-
3
- module Duct
4
- # Your code goes here...
5
- end
1
+ require 'duct/version'
2
+ require 'duct/runner'
3
+ require 'duct/cli'
data/lib/duct/cli.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'duct/runner'
2
+
3
+ module Duct
4
+ class Cli
5
+ BUNDLER_COMMANDS = %w{
6
+ update
7
+ check
8
+ list
9
+ show
10
+ outdated
11
+ console
12
+ open
13
+ viz
14
+ }
15
+
16
+ USAGE = %Q{Commands:
17
+ duct myscript.rb [param1 param2] # Installs bundle included in myscript.rb if needed and
18
+ # runs myscript with optional parameters.
19
+ duct update sinatra myscript.rb # Runs specified bundler command on the bundled included
20
+ # in myscript, passing the additional parameters. Available
21
+ # commands: #{BUNDLER_COMMANDS.join(', ')}.
22
+ # Run bundle help for more info.}
23
+
24
+ def initialize(args)
25
+ @args = args
26
+ end
27
+
28
+ def filename
29
+ command ? @args.last : @args.first
30
+ end
31
+
32
+ def command
33
+ @args[0..-2].join(' ') if BUNDLER_COMMANDS.include?(@args.first)
34
+ end
35
+
36
+ def params
37
+ command ? [] : @args[1..-1]
38
+ end
39
+
40
+ def error?
41
+ !(command || filename)
42
+ end
43
+
44
+ def run
45
+ if error?
46
+ puts(USAGE)
47
+ exit(-1)
48
+ end
49
+ runner.run
50
+ end
51
+
52
+ private
53
+
54
+ def runner
55
+ @runner ||= Duct::Runner.new(self)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,59 @@
1
+ require 'tmpdir'
2
+ require 'stringio'
3
+
4
+ module Duct
5
+ class Runner
6
+ def initialize(config)
7
+ @config = config
8
+ @script, @data = File.read(@config.filename).split(/^__END__$/, 2)
9
+ @preamble = @data.split(/^@@\s*(.*\S)\s*$/, 2).first
10
+ end
11
+
12
+ def run
13
+ copy_embedded_files
14
+ system "BUNDLE_GEMFILE=#{tempdir}/Gemfile bundle #{@config.command}"
15
+ update_embedded_files
16
+ exec "BUNDLE_GEMFILE=#{tempdir}/Gemfile bundle exec ruby #{@config.filename} #{@config.params.join(' ')}; rm -rf #{tempdir}" unless @config.command
17
+ end
18
+
19
+ private
20
+
21
+ def copy_embedded_files
22
+ embedded_files.each do |file, contents|
23
+ IO.write("#{tempdir}/#{file}", contents)
24
+ end
25
+ end
26
+
27
+ def update_embedded_files
28
+ contents = @script.dup
29
+
30
+ contents << "__END__"
31
+ contents << @preamble
32
+
33
+ Dir.glob("#{tempdir}/*") do |filename|
34
+ contents << "@@ #{File.basename(filename)}\n"
35
+ contents << File.read(filename)
36
+ end
37
+
38
+ IO.write(@config.filename, contents)
39
+ end
40
+
41
+ def embedded_files
42
+ @embedded_files ||= {}.tap do |files|
43
+ file = nil
44
+ @data.each_line do |line|
45
+ if line =~ /^@@\s*(.*\S)\s*$/
46
+ file = ''
47
+ files[$1.to_sym] = file
48
+ elsif file
49
+ file << line
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def tempdir
56
+ @tempdir ||= Dir.mktmpdir
57
+ end
58
+ end
59
+ end
data/lib/duct/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Duct
2
- VERSION = "0.0.0"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.color_enabled = true
3
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'duct/cli'
3
+
4
+ describe Duct::Cli do
5
+ subject { Duct::Cli.new(argv) }
6
+
7
+ context 'just filename' do
8
+ let(:argv) { ['myscript.rb'] }
9
+
10
+ its(:filename) { should == 'myscript.rb' }
11
+ its(:command) { should be_nil }
12
+ its(:params) { should be_empty }
13
+ its(:error?) { should be_false }
14
+ end
15
+
16
+ context 'filename and params' do
17
+ let(:argv) { ['myscript.rb', 'param1', 'param2'] }
18
+
19
+ its(:filename) { should == 'myscript.rb' }
20
+ its(:command) { should be_nil }
21
+ its(:params) { should == ['param1', 'param2'] }
22
+ its(:error?) { should be_false }
23
+ end
24
+
25
+ context 'command and filename' do
26
+ let(:argv) { ['update', 'myscript.rb'] }
27
+
28
+ its(:filename) { should == 'myscript.rb' }
29
+ its(:command) { should == 'update' }
30
+ its(:params) { should be_empty }
31
+ its(:error?) { should be_false }
32
+
33
+ context 'with params for the command' do
34
+ let(:argv) { ['update', 'sinatra', 'myscript.rb'] }
35
+
36
+ its(:filename) { should == 'myscript.rb' }
37
+ its(:command) { should == 'update sinatra' }
38
+ its(:params) { should be_empty }
39
+ its(:error?) { should be_false }
40
+ end
41
+ end
42
+
43
+ context 'errors' do
44
+ context 'nothing' do
45
+ let(:argv) { [] }
46
+
47
+ its(:error?) { should be_true }
48
+ end
49
+ end
50
+ end
metadata CHANGED
@@ -1,20 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Sergio Gil
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-01-05 00:00:00.000000000 Z
11
+ date: 2014-01-13 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
18
30
  requirements:
19
31
  - - ~>
20
32
  - !ruby/object:Gem::Version
@@ -22,7 +34,6 @@ dependencies:
22
34
  type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
38
  - - ~>
28
39
  - !ruby/object:Gem::Version
@@ -30,23 +41,36 @@ dependencies:
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: rake
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
- - - ! '>='
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
36
60
  - !ruby/object:Gem::Version
37
61
  version: '0'
38
62
  type: :development
39
63
  prerelease: false
40
64
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
65
  requirements:
43
- - - ! '>='
66
+ - - '>='
44
67
  - !ruby/object:Gem::Version
45
68
  version: '0'
46
- description: duct tape
69
+ description: Embeds a Gemfile in a script
47
70
  email:
48
71
  - sgilperez@gmail.com
49
- executables: []
72
+ executables:
73
+ - duct
50
74
  extensions: []
51
75
  extra_rdoc_files: []
52
76
  files:
@@ -55,33 +79,39 @@ files:
55
79
  - LICENSE.txt
56
80
  - README.md
57
81
  - Rakefile
82
+ - bin/duct
58
83
  - duct.gemspec
84
+ - examples/sinatra.rb
59
85
  - lib/duct.rb
86
+ - lib/duct/cli.rb
87
+ - lib/duct/runner.rb
60
88
  - lib/duct/version.rb
89
+ - spec/spec_helper.rb
90
+ - spec/unit/cli_spec.rb
61
91
  homepage: https://github.com/porras/duct
62
92
  licenses:
63
93
  - MIT
94
+ metadata: {}
64
95
  post_install_message:
65
96
  rdoc_options: []
66
97
  require_paths:
67
98
  - lib
68
99
  required_ruby_version: !ruby/object:Gem::Requirement
69
- none: false
70
100
  requirements:
71
- - - ! '>='
101
+ - - '>='
72
102
  - !ruby/object:Gem::Version
73
103
  version: '0'
74
104
  required_rubygems_version: !ruby/object:Gem::Requirement
75
- none: false
76
105
  requirements:
77
- - - ! '>='
106
+ - - '>='
78
107
  - !ruby/object:Gem::Version
79
108
  version: '0'
80
109
  requirements: []
81
110
  rubyforge_project:
82
- rubygems_version: 1.8.23
111
+ rubygems_version: 2.0.3
83
112
  signing_key:
84
- specification_version: 3
85
- summary: duct tape
86
- test_files: []
87
- has_rdoc:
113
+ specification_version: 4
114
+ summary: Embeds a Gemfile in a script
115
+ test_files:
116
+ - spec/spec_helper.rb
117
+ - spec/unit/cli_spec.rb