mutagem 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.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
+