mutagem 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ *.rb diff=ruby
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ coverage
5
+ rdoc
6
+ .yardoc
7
+ rerun.txt
8
+ tags
9
+ tmp/fixtures
10
+ tmp/aruba
11
+
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --verbose
2
+ --list-undoc
3
+ -
4
+ LICENSE
5
+ HISTORY.markdown
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in the .gemspec file
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mutagem (0.1.3)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ aruba (0.2.3)
10
+ background_process
11
+ cucumber (~> 0.9.0)
12
+ background_process (1.2)
13
+ builder (2.1.2)
14
+ cucumber (0.9.0)
15
+ builder (~> 2.1.2)
16
+ diff-lcs (~> 1.1.2)
17
+ gherkin (~> 2.2.2)
18
+ json (~> 1.4.6)
19
+ term-ansicolor (~> 1.0.5)
20
+ diff-lcs (1.1.2)
21
+ gherkin (2.2.4)
22
+ json (~> 1.4.6)
23
+ term-ansicolor (~> 1.0.5)
24
+ trollop (~> 1.16.2)
25
+ json (1.4.6)
26
+ rake (0.8.7)
27
+ rdiscount (1.6.5)
28
+ rspec (1.3.0)
29
+ term-ansicolor (1.0.5)
30
+ trollop (1.16.2)
31
+ yard (0.6.1)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ aruba (>= 0.2.0)
38
+ bundler (>= 1.0.0)
39
+ cucumber (>= 0.6)
40
+ mutagem!
41
+ rake (>= 0.8.7)
42
+ rdiscount (>= 1.6.5)
43
+ rspec (>= 1.2.9)
44
+ yard (>= 0.6.1)
data/HISTORY.markdown ADDED
@@ -0,0 +1,11 @@
1
+ History
2
+ =======
3
+ Most recent changes are at the top
4
+
5
+
6
+ Changes
7
+ -------
8
+
9
+ ### 0.1.3 - 10/01/2010 ###
10
+
11
+ * initial release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 GearheadForHire, LLC
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.markdown ADDED
@@ -0,0 +1,119 @@
1
+ Mutagem
2
+ ========
3
+
4
+ A Ruby gem for file based mutexes with a simple external process management wrapper.
5
+
6
+
7
+ Overview
8
+ --------
9
+ The Mutagem library provides file based mutexes for recursion protection and wrapper classes for
10
+ threading of external processes with support for output and exit status capturing.
11
+
12
+ A test suite is provided for both unit testing with [RSpec](http://github.com/dchelimsky/rspec)
13
+ and functional testing with [Cucumber](http://github.com/aslakhellesoy/cucumber). The code is
14
+ documented using [YARD](http://github.com/lsegal/yard).
15
+
16
+
17
+ Example Usage
18
+ -------------
19
+ The following Ruby code is used to run a word by word diff on two folders of comma delimited data.
20
+ Each folder contains before and after CSV dumps from a SQL database. The CSV files have the same name
21
+ in each of the two folders.
22
+
23
+ Mutagem is providing recursion protection. The recursion protection is very useful if the script is
24
+ run in an automated environment (ex. cron). Mutagem is also capturing output and exit status for the
25
+ diff processes allowing customized output.
26
+
27
+ Standard diff is quick but it can't give you a word by word diff of CSV data. Word by word
28
+ colorized diffing with support for custom delimiters is provided
29
+ by [dwdiff](http://os.ghalkes.nl/dwdiff.html).
30
+
31
+
32
+ #!/usr/bin/env ruby
33
+
34
+ require 'rubygems'
35
+ require 'mutagem'
36
+ require 'pathname'
37
+ require 'term/ansicolor'
38
+
39
+ class String
40
+ include Term::ANSIColor
41
+ end
42
+
43
+ lock_was_sucessful = Mutagem::Mutex.new('diff.lck').execute do
44
+
45
+ $stdout.sync = true # force screen updates
46
+ before_files = Dir.glob('test/dump/before/*.csv')
47
+
48
+ before_files.each do |bf|
49
+
50
+ af = 'test/dump/after/' + Pathname.new(bf).basename.to_s
51
+
52
+ # quick diff
53
+ cmd = "diff #{bf} #{af}"
54
+ task = Mutagem::Task.new(cmd)
55
+ task.join
56
+
57
+ if (task.exitstatus == 0)
58
+ # no changes, show a "still working" indicator
59
+ print ".".green
60
+ else
61
+ # we have changes, slow diff, word based and CSV (comma) sensitive
62
+ print "D".red
63
+ puts "\n#{af}"
64
+
65
+ cmd = "dwdiff --color --context=0 --delimiters=, #{bf} #{af}"
66
+ task = Mutagem::Task.new(cmd)
67
+ task.join
68
+
69
+ puts task.output
70
+ end
71
+
72
+ end
73
+ puts "\n"
74
+
75
+ end
76
+ puts "process locked" unless lock_was_sucessful
77
+
78
+
79
+ System Requirements
80
+ -------------------
81
+ * POSIX system (tested on Linux and Windows/Cygwin environments)
82
+
83
+
84
+ Installation
85
+ ------------
86
+ Mutagem is avaliable on [RubyGems.org](http://rubygems.org/gems/mutagem)
87
+
88
+ gem install mutagem
89
+
90
+
91
+ Development
92
+ -----------
93
+
94
+ Mutagem uses [Bundler](http://github.com/carlhuda/bundler) to manage dependencies, the gemspec
95
+ file is maintained by hand.
96
+
97
+ git clone http://github.com/robertwahler/mutagem
98
+ cd mutagem
99
+
100
+ Use bundle to install development dependencies
101
+
102
+ bundle install
103
+
104
+ rake -T
105
+
106
+ rake build # Build mutagem-0.1.2.gem into the pkg directory
107
+ rake doc:clean # Remove generated documenation
108
+ rake doc:generate # Generate YARD Documentation
109
+ rake features # Run Cucumber features
110
+ rake install # Build and install mutagem-0.1.2.gem into system gems
111
+ rake release # Create tag v0.1.2 and build and push mutagem-0.1.2.gem to Rubygems
112
+ rake spec # Run specs
113
+ rake test # Run specs and features
114
+
115
+
116
+ Copyright
117
+ ---------
118
+
119
+ Copyright (c) 2010 GearheadForHire, LLC. See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ # bundler/setup is managing $LOAD_PATH, any gem needed by this Rakefile must
4
+ # be listed as a development dependency in the gemspec
5
+
6
+ require 'rubygems'
7
+ require 'bundler/setup'
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ def gemspec
12
+ @gemspec ||= begin
13
+ file = File.expand_path('../mutagem.gemspec', __FILE__)
14
+ eval(File.read(file), binding, file)
15
+ end
16
+ end
17
+
18
+ require 'spec'
19
+ require 'spec/rake/spectask'
20
+ Spec::Rake::SpecTask.new(:spec) do |spec|
21
+ spec.libs << 'lib' << 'spec'
22
+ spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ require 'cucumber'
26
+ require 'cucumber/rake/task'
27
+ Cucumber::Rake::Task.new(:features) do |task|
28
+ task.cucumber_opts = ["features"]
29
+ end
30
+
31
+ desc "Run specs and features"
32
+ task :test => [:spec, :features]
33
+
34
+ task :default => :test
35
+
36
+ namespace :doc do
37
+ project_root = File.expand_path(File.dirname(__FILE__))
38
+ doc_destination = File.join(project_root, 'rdoc')
39
+
40
+ require 'yard'
41
+ require 'yard/rake/yardoc_task'
42
+
43
+ YARD::Rake::YardocTask.new(:generate) do |yt|
44
+ yt.options = ['--markup-provider', 'rdiscount',
45
+ '--output-dir', doc_destination
46
+ ] +
47
+ gemspec.rdoc_options - ['--line-numbers', '--inline-source']
48
+ end
49
+
50
+ desc "Remove generated documenation"
51
+ task :clean do
52
+ rm_r doc_destination if File.exists?(doc_destination)
53
+ end
54
+
55
+ end
data/TODO.markdown ADDED
@@ -0,0 +1,6 @@
1
+ TODO
2
+ ====
3
+
4
+ * update readme with examples of dwdiff usage
5
+ * add tasker
6
+ * test under Windows/Cygwin
@@ -0,0 +1,7 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format pretty features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "#{rerun_opts} --format rerun --out rerun.txt --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %>
7
+ wip: --tags @wip:3 --wip features
@@ -0,0 +1,22 @@
1
+ @announce
2
+ Feature: File based mutexes
3
+
4
+ Automated processes need locking to prevent recursion on long running commands
5
+
6
+ Scenario: Process runs with no lock file present
7
+ Given a Ruby source file that uses Mutagem::Mutex named "test.rb"
8
+ When I run "ruby test.rb"
9
+ Then the exit status should be 0
10
+ And the output should contain:
11
+ """
12
+ hello world
13
+ """
14
+
15
+ Scenario: Process runs with a lock file present
16
+ Given a Ruby source file that uses Mutagem::Mutex named "test.rb"
17
+ When I run with a lock file present "ruby test.rb"
18
+ Then the exit status should be 1
19
+ And the output should not contain:
20
+ """
21
+ hello world
22
+ """
File without changes
@@ -0,0 +1,51 @@
1
+
2
+ Given /^a Ruby source file that uses Mutagem::Mutex named "([^\"]*)"$/ do |filename|
3
+ steps %Q{
4
+ Given a file named "#{filename}" with:
5
+ """
6
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__) unless
7
+ $LOAD_PATH.include? File.expand_path('../../../lib', __FILE__)
8
+
9
+ require 'mutagem'
10
+
11
+ # make sure we are working with the expected gem
12
+ raise "unexpected mutagem version" unless Mutagem::VERSION == '#{Mutagem::VERSION}'
13
+
14
+ mutext = Mutagem::Mutex.new
15
+ mutext.execute do
16
+ puts "hello world"
17
+ exit 0
18
+ end
19
+ exit 1
20
+ """
21
+ }
22
+ end
23
+
24
+ Given /^a Ruby source file that uses Mutagem::Task named "([^\"]*)"$/ do |filename|
25
+ steps %Q{
26
+ Given a file named "#{filename}" with:
27
+ """
28
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__) unless
29
+ $LOAD_PATH.include? File.expand_path('../../../lib', __FILE__)
30
+
31
+ require 'mutagem'
32
+
33
+ # make sure we are working with the expected gem
34
+ raise "unexpected mutagem version" unless Mutagem::VERSION == '#{Mutagem::VERSION}'
35
+
36
+ cmd = %q[ruby -e 'puts "hello world"; exit 2']
37
+ task = Mutagem::Task.new(cmd)
38
+ task.join
39
+
40
+ puts task.output
41
+ exit task.exitstatus
42
+ """
43
+ }
44
+ end
45
+
46
+ When /^I run with a lock file present "(.*)"$/ do |cmd|
47
+ lockfile = File.join(current_dir, 'mutagem.lck')
48
+ Mutagem::Mutex.new(lockfile).execute do
49
+ run(unescape(cmd), false)
50
+ end
51
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'mutagem'
3
+ require 'aruba'
4
+ require 'spec/expectations'
@@ -0,0 +1,15 @@
1
+ @announce
2
+ Feature: Simple process management wrapper
3
+
4
+ Manage subprocess tasks in a separate thread
5
+ in order to capture the output and manage additional tasks
6
+ based on the subprocess exit status
7
+
8
+ Scenario: Sucessfully run a subprocess
9
+ Given a Ruby source file that uses Mutagem::Task named "tasker.rb"
10
+ When I run "ruby tasker.rb"
11
+ Then the exit status should be 2
12
+ And the output should contain:
13
+ """
14
+ hello world
15
+ """
@@ -0,0 +1,58 @@
1
+ module Mutagem
2
+
3
+ # File locking wrapper for Flock
4
+ class Lockfile
5
+ # filename for the lockfile, can include path
6
+ attr_accessor :lockfile
7
+
8
+ # Create a new LockFile
9
+ #
10
+ # @param [String] lockfile filename
11
+ def initialize(lockfile=nil)
12
+ raise ArgumentError, "lockfile not specified" unless lockfile
13
+ @lockfile = lockfile
14
+ end
15
+
16
+ # Does another process have a lock?
17
+ # True if we can't get an exclusive lock
18
+ def locked?
19
+ return false unless File.exists?(lockfile)
20
+ result = false
21
+ open(lockfile, 'w') do |f|
22
+ # exclusive non-blocking lock
23
+ result = !lock(f, File::LOCK_EX | File::LOCK_NB)
24
+ end
25
+ result
26
+ end
27
+
28
+ # Get a file lock with flock and ensure the
29
+ # lock is removed (but not the lockfile). Accepts an optional
30
+ # code block.
31
+ #
32
+ # @example
33
+ #
34
+ # open('output', 'w') do |f|
35
+ # # exclusive blocking lock
36
+ # lock(f, File::LOCK_EX) do |f|
37
+ # f << "write to file while blocking other processes"
38
+ # end
39
+ # end
40
+ #
41
+ # @param [Object] file the file IO object returned from a call to "open(filename, mode_string)"
42
+ # @param [Constant] mode locking_constant, see File
43
+ # @return [Boolean] 0 or false if unable to sucessfully lock
44
+ def lock(file, mode)
45
+ result = file.flock(mode)
46
+ if result
47
+ begin
48
+ yield file if block_given? # may not have block if called by locked?
49
+ ensure
50
+ # unlock but leave the file on the filesystem
51
+ file.flock(File::LOCK_UN)
52
+ end
53
+ end
54
+ return result
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,47 @@
1
+ module Mutagem
2
+
3
+ # File based mutex
4
+ class Mutex < Lockfile
5
+
6
+ # Creates a new Mutex
7
+ #
8
+ # @param [String] lockfile filename
9
+ def initialize(lockfile='mutagem.lck')
10
+ super lockfile
11
+ end
12
+
13
+ # Protect a block
14
+ #
15
+ # @example
16
+ #
17
+ # require 'rubygems'
18
+ # require 'mutagem'
19
+ #
20
+ # mutex = Mutagem::Mutex.new("my_process_name.lck")
21
+ # mutex.execute do
22
+ # puts "this block is protected from recursion"
23
+ # end
24
+ #
25
+ # @param block the block of code to protect with the mutex
26
+ # @return [Boolean] 0 if lock sucessful, otherwise false
27
+ def execute(&block)
28
+ result = false
29
+ raise ArgumentError, "missing block" unless block_given?
30
+
31
+ begin
32
+ open(lockfile, 'w') do |f|
33
+ # exclusive non-blocking lock
34
+ result = lock(f, File::LOCK_EX | File::LOCK_NB) do |f|
35
+ yield
36
+ end
37
+ end
38
+ ensure
39
+ # clean up but only if we have a positive result meaning we wrote the lockfile
40
+ FileUtils.rm(lockfile) if (result && File.exists?(lockfile))
41
+ end
42
+
43
+ result
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,66 @@
1
+ require 'thread'
2
+
3
+ module Mutagem
4
+
5
+ # A simple external process management wrapper
6
+ #
7
+ # @example
8
+ #
9
+ # cmd = "diff file1.txt file2.txt"
10
+ # task = Mutagem::Task.new(cmd)
11
+ # task.join
12
+ #
13
+ # if (task.exitstatus == 0)
14
+ # puts "files match"
15
+ # end
16
+ class Task
17
+ # @return [String] command to run
18
+ attr_reader :cmd
19
+ attr_accessor :thread
20
+
21
+ # Create a new Task
22
+ #
23
+ # @param [String] cmd the cmd to execute
24
+ def initialize(cmd)
25
+ @cmd = cmd
26
+ @thread = Thread.new do
27
+ pipe = IO.popen(cmd + " 2>&1")
28
+ @pid = pipe.pid
29
+ begin
30
+ @output = pipe.readlines
31
+ pipe.close
32
+ @exitstatus = $?.exitstatus
33
+ rescue => e
34
+ @exception = e
35
+ end
36
+ end
37
+ end
38
+
39
+ # @return [Array] array of strings from the subprocess output
40
+ def output
41
+ @output
42
+ end
43
+
44
+ # @return subprocess exit status
45
+ def exitstatus
46
+ @exitstatus
47
+ end
48
+
49
+ # @return subprocess pid
50
+ def pid
51
+ @pid
52
+ end
53
+
54
+ # @return [Exception] exception returned if one is thrown by Task
55
+ def exception
56
+ @exception
57
+ end
58
+
59
+ # join the task's thead and wait for it to finish
60
+ def join
61
+ thread.join
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,3 @@
1
+ module Mutagem
2
+ VERSION = "0.1.3" unless defined?(::Mutagem::VERSION)
3
+ end
data/lib/mutagem.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'mutagem/version'
2
+ require 'mutagem/lockfile'
3
+ require 'mutagem/mutex'
4
+ require 'mutagem/task'
5
+
6
+ module Mutagem
7
+
8
+ end
9
+
data/mutagem.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/mutagem/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "mutagem"
6
+ s.version = Mutagem::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Robert Wahler"]
9
+ s.email = ["robert@gearheadforhire.com"]
10
+ s.homepage = "http://rubygems.org/gems/mutagem"
11
+ s.summary = "File based mutexes with a simple external process management wrapper"
12
+ s.description = "The Mutagem library provides file based mutexes for recursion protection and
13
+ classes for threading of external processes with support for output and
14
+ exit status capturing. A test suite is provided for both unit and functional testing.
15
+ The code is documented using YARD."
16
+
17
+ s.required_rubygems_version = ">= 1.3.6"
18
+ s.rubyforge_project = "mutagem"
19
+
20
+ s.add_development_dependency "bundler", ">= 1.0.0"
21
+ s.add_development_dependency "rspec", ">= 1.2.9"
22
+ s.add_development_dependency "cucumber", ">= 0.6"
23
+ s.add_development_dependency "aruba", ">= 0.2.0"
24
+ s.add_development_dependency "rake", ">= 0.8.7"
25
+ s.add_development_dependency "yard", ">= 0.6.1"
26
+ s.add_development_dependency "rdiscount", ">= 1.6.5"
27
+
28
+ s.files = `git ls-files`.split("\n")
29
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
30
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
31
+ s.require_path = 'lib'
32
+
33
+ s.has_rdoc = 'yard'
34
+ s.rdoc_options = [
35
+ '--title', 'Mutagem Documentation',
36
+ '--main', 'README.markdown',
37
+ '--line-numbers',
38
+ '--inline-source'
39
+ ]
40
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Mutagem do
4
+
5
+ describe 'VERSION' do
6
+
7
+ it "should return a string formatted '#.#.#'" do
8
+ Mutagem::VERSION.should match(/(^[\d]+\.[\d]+\.[\d]+$)/)
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Mutagem::Lockfile do
4
+
5
+ before(:each) do
6
+ # remove tmp/aruba
7
+ FileUtils.rm_rf(current_dir)
8
+ end
9
+
10
+ it "should raise ArgumentError if initialized without a lock filename" do
11
+ in_current_dir do
12
+ lambda {Mutagem::Lockfile.new}.should raise_error(ArgumentError, 'lockfile not specified')
13
+ lambda {Mutagem::Lockfile.new('mylock.lock')}.should_not raise_error
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Mutagem::Mutex do
4
+
5
+ before(:each) do
6
+ # remove tmp/aruba
7
+ FileUtils.rm_rf(current_dir)
8
+ end
9
+
10
+ it "should create a mutex, yield, and clean up" do
11
+ in_current_dir do
12
+ mutex = Mutagem::Mutex.new
13
+ result = mutex.execute do
14
+ File.should be_file('mutagem.lck')
15
+ mutex.should be_locked
16
+ end
17
+ result.should be_true
18
+ mutex.should_not be_locked
19
+ File.should_not be_file('mutagem.lck')
20
+ end
21
+ end
22
+
23
+ it "should prevent recursion but not block" do
24
+ in_current_dir do
25
+ Mutagem::Mutex.new.execute do
26
+ File.should be_file('mutagem.lck')
27
+
28
+ mutex = Mutagem::Mutex.new
29
+ result = mutex.execute do
30
+ # This block is protected, should not be here
31
+ true.should be(false)
32
+ end
33
+ result.should be_false
34
+ mutex.should be_locked
35
+ end
36
+ File.should_not be_file('mutagem.lck')
37
+ end
38
+ end
39
+
40
+ it "should raise ArgumentError unless a block is given" do
41
+ in_current_dir do
42
+ mutex = Mutagem::Mutex.new
43
+ lambda {result = mutex.execute}.should raise_error(ArgumentError, 'missing block')
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format nested
@@ -0,0 +1,19 @@
1
+ $LOAD_PATH.unshift File.expand_path('..', __FILE__) unless
2
+ $LOAD_PATH.include? File.expand_path('..', __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) unless
4
+ $LOAD_PATH.include? File.expand_path('../../lib', __FILE__)
5
+
6
+ require 'rubygems'
7
+ require 'mutagem'
8
+ require 'spec'
9
+ require 'spec/autorun'
10
+ require 'aruba/api'
11
+
12
+ # aruba helper, returns full path to files in the aruba tmp folder
13
+ def fullpath(filename)
14
+ File.expand_path(File.join(current_dir, filename))
15
+ end
16
+
17
+ Spec::Runner.configure do |config|
18
+ config.include Aruba::Api
19
+ end
data/spec/watchr.rb ADDED
@@ -0,0 +1,142 @@
1
+ # Watchr: Autotest like functionality
2
+ #
3
+ # Run me with:
4
+ #
5
+ # $ watchr spec/watchr.rb
6
+
7
+ require 'term/ansicolor'
8
+
9
+ $c = Term::ANSIColor
10
+
11
+ def getch
12
+ state = `stty -g`
13
+ begin
14
+ `stty raw -echo cbreak`
15
+ $stdin.getc
16
+ ensure
17
+ `stty #{state}`
18
+ end
19
+ end
20
+
21
+ # --------------------------------------------------
22
+ # Convenience Methods
23
+ # --------------------------------------------------
24
+ def all_feature_files
25
+ Dir['features/*.feature']
26
+ end
27
+
28
+ def all_spec_files
29
+ files = Dir['spec/revenc/*.rb']
30
+ end
31
+
32
+ def run(cmd)
33
+
34
+ pid = fork do
35
+ puts "\n"
36
+ print $c.cyan, cmd, $c.clear, "\n"
37
+ exec(cmd)
38
+ end
39
+ Signal.trap('INT') do
40
+ puts "sending KILL to pid: #{pid}"
41
+ Process.kill("KILL", pid)
42
+ end
43
+ Process.waitpid(pid)
44
+
45
+ prompt
46
+ end
47
+
48
+ def run_all
49
+ run_all_specs
50
+ run_default_cucumber
51
+ end
52
+
53
+ # allow cucumber rerun.txt smarts
54
+ def run_default_cucumber
55
+ cmd = "cucumber"
56
+ run(cmd)
57
+ end
58
+
59
+ def run_all_features
60
+ cmd = "cucumber #{all_feature_files.join(' ')}"
61
+ run(cmd)
62
+ end
63
+
64
+ def run_feature(feature)
65
+ cmd = "cucumber #{feature}"
66
+ $last_feature = feature
67
+ run(cmd)
68
+ end
69
+
70
+ def run_last_feature
71
+ run_feature($last_feature) if $last_feature
72
+ end
73
+
74
+ def run_default_spec
75
+ cmd = "spec --color --format s ./spec"
76
+ run(cmd)
77
+ end
78
+
79
+ def run_all_specs
80
+ cmd = "spec --color --format s #{all_spec_files.join(' ')}"
81
+ p cmd
82
+ run(cmd)
83
+ end
84
+
85
+ def run_spec(spec)
86
+ cmd = "spec --color --format s #{spec}"
87
+ $last_spec = spec
88
+ run(cmd)
89
+ end
90
+
91
+ def run_last_spec
92
+ run_spec($last_spec) if $last_spec
93
+ end
94
+
95
+ def prompt
96
+ puts "Ctrl-\\ for menu, Ctrl-C to quit"
97
+ end
98
+
99
+ # init
100
+ $last_feature = nil
101
+ prompt
102
+
103
+ # --------------------------------------------------
104
+ # Watchr Rules
105
+ # --------------------------------------------------
106
+ #watch( '^features/(.*)\.feature' ) { |m| run_feature(m[0]) }
107
+ watch( '^features/(.*)\.feature' ) { run_default_cucumber }
108
+
109
+ watch( '^bin/(.*)' ) { run_default_cucumber }
110
+ watch( '^lib/(.*)' ) { run_default_cucumber }
111
+
112
+ watch( '^features/step_definitions/(.*)\.rb' ) { run_default_cucumber }
113
+ watch( '^features/support/(.*)\.rb' ) { run_default_cucumber }
114
+
115
+ watch( '^spec/(.*)_spec\.rb' ) { |m| run_spec(m[0]) }
116
+ # watch( '^lib/revenc/io.rb' ) { run_default_spec }
117
+ watch( '^lib/revenc/errors.rb' ) { run_default_spec }
118
+ watch( '^lib/revenc/lockfile.rb' ) { run_default_spec }
119
+
120
+ # --------------------------------------------------
121
+ # Signal Handling
122
+ # --------------------------------------------------
123
+
124
+ # Ctrl-\
125
+ Signal.trap('QUIT') do
126
+
127
+ puts "\n\nMENU: a = all , f = features s = specs, l = last feature (#{$last_feature ? $last_feature : 'none'}), q = quit\n\n"
128
+ c = getch
129
+ puts c.chr
130
+ if c.chr == "a"
131
+ run_all
132
+ elsif c.chr == "f"
133
+ run_default_cucumber
134
+ elsif c.chr == "s"
135
+ run_all_specs
136
+ elsif c.chr == "q"
137
+ abort("exiting\n")
138
+ elsif c.chr == "l"
139
+ run_last_feature
140
+ end
141
+
142
+ end
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mutagem
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 3
9
+ version: 0.1.3
10
+ platform: ruby
11
+ authors:
12
+ - Robert Wahler
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-01 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: bundler
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 0
30
+ - 0
31
+ version: 1.0.0
32
+ type: :development
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 2
45
+ - 9
46
+ version: 1.2.9
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: cucumber
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ - 6
60
+ version: "0.6"
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: aruba
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ - 2
74
+ - 0
75
+ version: 0.2.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
80
+ name: rake
81
+ requirement: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ - 8
89
+ - 7
90
+ version: 0.8.7
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: *id005
94
+ - !ruby/object:Gem::Dependency
95
+ name: yard
96
+ requirement: &id006 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ segments:
102
+ - 0
103
+ - 6
104
+ - 1
105
+ version: 0.6.1
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: *id006
109
+ - !ruby/object:Gem::Dependency
110
+ name: rdiscount
111
+ requirement: &id007 !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ segments:
117
+ - 1
118
+ - 6
119
+ - 5
120
+ version: 1.6.5
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *id007
124
+ description: |-
125
+ The Mutagem library provides file based mutexes for recursion protection and
126
+ classes for threading of external processes with support for output and
127
+ exit status capturing. A test suite is provided for both unit and functional testing.
128
+ The code is documented using YARD.
129
+ email:
130
+ - robert@gearheadforhire.com
131
+ executables: []
132
+
133
+ extensions: []
134
+
135
+ extra_rdoc_files: []
136
+
137
+ files:
138
+ - .gitattributes
139
+ - .gitignore
140
+ - .yardopts
141
+ - Gemfile
142
+ - Gemfile.lock
143
+ - HISTORY.markdown
144
+ - LICENSE
145
+ - README.markdown
146
+ - Rakefile
147
+ - TODO.markdown
148
+ - config/cucumber.yml
149
+ - features/mutex.feature
150
+ - features/step_definitions/.gitignore
151
+ - features/step_definitions/mutagem_steps.rb
152
+ - features/support/env.rb
153
+ - features/task.feature
154
+ - lib/mutagem.rb
155
+ - lib/mutagem/lockfile.rb
156
+ - lib/mutagem/mutex.rb
157
+ - lib/mutagem/task.rb
158
+ - lib/mutagem/version.rb
159
+ - mutagem.gemspec
160
+ - spec/basic_gem/basic_gem_spec.rb
161
+ - spec/mutagem/lockfile_spec.rb
162
+ - spec/mutagem/mutex_spec.rb
163
+ - spec/spec.opts
164
+ - spec/spec_helper.rb
165
+ - spec/watchr.rb
166
+ has_rdoc: yard
167
+ homepage: http://rubygems.org/gems/mutagem
168
+ licenses: []
169
+
170
+ post_install_message:
171
+ rdoc_options:
172
+ - --title
173
+ - Mutagem Documentation
174
+ - --main
175
+ - README.markdown
176
+ - --line-numbers
177
+ - --inline-source
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ none: false
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ hash: 723877775
186
+ segments:
187
+ - 0
188
+ version: "0"
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ segments:
195
+ - 1
196
+ - 3
197
+ - 6
198
+ version: 1.3.6
199
+ requirements: []
200
+
201
+ rubyforge_project: mutagem
202
+ rubygems_version: 1.3.7
203
+ signing_key:
204
+ specification_version: 3
205
+ summary: File based mutexes with a simple external process management wrapper
206
+ test_files: []
207
+