davidlee-state-fu 0.11.1 → 0.12.0

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/lib/lathe.rb CHANGED
@@ -58,6 +58,17 @@ module StateFu
58
58
  machine.lathe
59
59
  end
60
60
 
61
+ alias_method :context, :state_or_event
62
+
63
+ def context_state
64
+ state_or_event if state_or_event.is_a?(State)
65
+ end
66
+
67
+ def context_event
68
+ state_or_event if state_or_event.is_a?(Event)
69
+ end
70
+
71
+
61
72
  #
62
73
  # methods for extending the DSL
63
74
  #
@@ -68,11 +79,17 @@ module StateFu
68
79
  end
69
80
 
70
81
  # helpers are mixed into all binding / transition contexts
71
- def tool( *modules )
82
+ def tool( *modules, &block )
72
83
  machine.tool *modules
84
+ if block_given?
85
+ tool = Module.new
86
+ tool.module_eval &block
87
+ machine.tools << tool
88
+ end
73
89
  # inject them into self for immediate use
74
90
  modules.flatten.extend( ToolArray ).inject_into( self )
75
91
  end
92
+ alias_method :extend_dsl, :tool
76
93
 
77
94
  #
78
95
  # event definition methods
@@ -514,7 +531,7 @@ module StateFu
514
531
  end
515
532
  args.map do |name|
516
533
  self.send type, name, options.dup, &block
517
- end.extend mod
534
+ end.extend(mod)
518
535
  end
519
536
 
520
537
  end
data/lib/machine.rb CHANGED
@@ -4,7 +4,7 @@ module StateFu
4
4
  def self.BINDINGS
5
5
  @@_bindings ||= {}
6
6
  end
7
-
7
+
8
8
  include Applicable
9
9
  include HasOptions
10
10
 
@@ -17,10 +17,9 @@ module StateFu
17
17
  def self.for_class(klass, name, options={}, &block)
18
18
  options.symbolize_keys!
19
19
  name = name.to_sym
20
-
21
20
  unless machine = klass.state_fu_machines[ name ]
22
21
  machine = new(options)
23
- machine.bind! klass, name, options[:field_name]
22
+ machine.bind! klass, name, options
24
23
  end
25
24
  if block_given?
26
25
  machine.apply! &block
@@ -30,26 +29,36 @@ module StateFu
30
29
 
31
30
  # make it so that a class which has included StateFu has a binding to
32
31
  # this machine
33
- def self.bind!( machine, owner, name, field_name)
32
+ def self.bind!(machine, owner, name, options={})
34
33
  name = name.to_sym
34
+ options[:define_methods] = (name == DEFAULT) unless options.symbolize_keys!.has_key?(:define_methods)
35
+ options[:field_name] ||= Persistence.default_field_name(name)
36
+ options[:singleton] = true unless owner.is_a?(Class)
35
37
  # define an accessor method with the given name
36
- if owner.class == Class
37
- owner.state_fu_machines[name] = machine
38
- owner.state_fu_field_names[name] = field_name
38
+ if options[:singleton]
39
+ _binding = StateFu::Binding.new machine, owner, name, options
40
+ MethodFactory.define_singleton_method(owner, name) { _binding }
41
+ if alias_name = options[:alias] || options[:as]
42
+ MethodFactory.define_singleton_method(owner, alias_name) { _binding }
43
+ end
44
+ else
45
+ owner.state_fu_machines[name] = machine
46
+ owner.state_fu_options[name] = options
39
47
  # method_missing to catch NoMethodError for event methods, etc
40
- StateFu::MethodFactory.define_once_only_method_missing( owner )
41
- unless owner.respond_to?(name)
48
+ StateFu::MethodFactory.define_once_only_method_missing owner
49
+ unless owner.respond_to? name
42
50
  owner.class_eval do
43
51
  define_method name do
44
- state_fu( name )
52
+ state_fu name
53
+ end
54
+ # allow aliases to be set up, e.g. machine(:as => :status)
55
+ if alias_name = options[:alias] || options[:as]
56
+ alias_method alias_name, name
45
57
  end
46
58
  end
47
59
  end
48
60
  # prepare the persistence field
49
- StateFu::Persistence.prepare_field owner, field_name
50
- else
51
- _binding = StateFu::Binding.new machine, owner, name, :field_name => field_name, :singleton => true
52
- MethodFactory.define_singleton_method(owner, name) { _binding }
61
+ StateFu::Persistence.prepare_field owner, options[:field_name]
53
62
  end
54
63
  end
55
64
 
@@ -116,9 +125,8 @@ module StateFu
116
125
 
117
126
  # make it so a class which has included StateFu has a binding to
118
127
  # this machine
119
- def bind!( owner, name= DEFAULT, field_name = nil )
120
- field_name ||= Persistence.default_field_name( name )
121
- self.class.bind!(self, owner, name, field_name)
128
+ def bind!(owner, name=DEFAULT, options={})
129
+ self.class.bind!(self, owner, name, options)
122
130
  end
123
131
 
124
132
  def empty?
@@ -7,14 +7,15 @@ module StateFu
7
7
 
8
8
  class MethodFactory
9
9
  attr_accessor :method_definitions
10
- attr_reader :binding
11
-
10
+ attr_reader :binding, :machine
11
+
12
12
  # An instance of MethodFactory is created to define methods on a specific StateFu::Binding, and
13
13
  # on the object it is bound to.
14
14
 
15
- def initialize( _binding )
16
- @binding = _binding
17
- simple_events, complex_events = @binding.machine.events.partition(&:simple?)
15
+ def initialize(_binding)
16
+ @binding = _binding
17
+ @machine = binding.machine
18
+ simple_events, complex_events = machine.events.partition &:simple?
18
19
  @method_definitions = {}
19
20
 
20
21
  # simple event methods
@@ -95,7 +96,7 @@ module StateFu
95
96
  end unless event.targets.nil?
96
97
  end
97
98
 
98
- @binding.machine.states.each do |state|
99
+ machine.states.each do |state|
99
100
  method_definitions["#{state.name}?"] = lambda do
100
101
  _binding.current_state == state
101
102
  end
@@ -114,9 +115,9 @@ module StateFu
114
115
  # Note this happens when a machine is first bound to the class,
115
116
  # not when StateFu is included.
116
117
 
117
- def self.prepare_class( klass )
118
+ def self.prepare_class(klass)
118
119
  raise caller.inspect
119
- self.define_once_only_method_missing( klass )
120
+ self.define_once_only_method_missing(klass)
120
121
  end # prepare_class
121
122
 
122
123
  # When triggered, method_missing will first call state_fu!,
@@ -137,7 +138,7 @@ module StateFu
137
138
  # or thoroughly understand what's happening in
138
139
  # MethodFactory#define_once_only_method_missing.
139
140
 
140
- def self.define_once_only_method_missing( klass )
141
+ def self.define_once_only_method_missing(klass)
141
142
  raise ArgumentError.new(klass.to_s) unless klass.is_a?(Class)
142
143
 
143
144
  klass.class_eval do
@@ -160,14 +161,14 @@ module StateFu
160
161
  end
161
162
 
162
163
  # call the newly defined method, or the original method_missing
163
- if respond_to?(method_name, true)
164
+ if respond_to? method_name, true
164
165
  # it was defined by calling state_fu!, which instantiated bindings
165
166
  # for its state machines, which defined singleton methods for its
166
167
  # states & events when it was constructed.
167
- __send__( method_name, *args, &block )
168
+ __send__ method_name, *args, &block
168
169
  else
169
170
  # call the original method_missing (method_missing_before_state_fu)
170
- method_missing( method_name, *args, &block )
171
+ method_missing method_name, *args, &block
171
172
  end
172
173
  end # method_missing
173
174
  end # class_eval
@@ -177,8 +178,8 @@ module StateFu
177
178
  # object. Any existing methods will not be tampered with, but a
178
179
  # warning will be issued in the logs if any methods cannot be defined.
179
180
  def install!
180
- define_event_methods_on( @binding )
181
- define_event_methods_on( @binding.object )
181
+ define_event_methods_on @binding
182
+ define_event_methods_on @binding.object if @binding.options[:define_methods]
182
183
  end
183
184
 
184
185
  #
@@ -202,13 +203,13 @@ module StateFu
202
203
  # itself. The remaining arguments are passed into the transition,
203
204
  # as with simple event methods.
204
205
  #
205
- def define_event_methods_on( obj )
206
+ def define_event_methods_on(obj)
206
207
  method_definitions.each do |method_name, method_body|
207
- define_singleton_method( obj, method_name, &method_body)
208
+ define_singleton_method obj, method_name, &method_body
208
209
  end
209
210
  end # define_event_methods_on
210
211
 
211
- def define_singleton_method( object, method_name, &block )
212
+ def define_singleton_method(object, method_name, &block)
212
213
  MethodFactory.define_singleton_method object, method_name, &block
213
214
  end
214
215
 
@@ -221,8 +222,8 @@ module StateFu
221
222
  #
222
223
  # existing methods will never be overwritten.
223
224
 
224
- def self.define_singleton_method( object, method_name, options={}, &block )
225
- if object.respond_to?(method_name, true)
225
+ def self.define_singleton_method(object, method_name, options={}, &block)
226
+ if object.respond_to? method_name, true
226
227
  msg = !options[:force]
227
228
  Logger.info "Existing method #{method(method_name) rescue [method_name].inspect} "\
228
229
  "for #{object.class} #{object} "\
@@ -231,7 +232,7 @@ module StateFu
231
232
  else
232
233
  metaclass = class << object; self; end
233
234
  metaclass.class_eval do
234
- define_method( method_name, &block )
235
+ define_method method_name, &block
235
236
  end
236
237
  end
237
238
  end
data/lib/persistence.rb CHANGED
@@ -39,7 +39,7 @@ module StateFu
39
39
  end
40
40
 
41
41
  # returns the appropriate persister class for the given class & field name.
42
- def self.class_for( klass, field_name )
42
+ def self.class_for(klass, field_name)
43
43
  raise ArgumentError if [klass, field_name].any?(&:nil?)
44
44
  @@class_for[klass] ||= {}
45
45
  @@class_for[klass][field_name] ||=
@@ -52,7 +52,7 @@ module StateFu
52
52
  end
53
53
  end
54
54
 
55
- def self.for_class( klass, binding, field_name )
55
+ def self.for_class(klass, binding, field_name)
56
56
  persister_class = class_for klass, field_name
57
57
  prepare_field( klass, field_name, persister_class)
58
58
  returning persister_class.new( binding, field_name ) do |persister|
@@ -60,7 +60,7 @@ module StateFu
60
60
  end
61
61
  end
62
62
 
63
- def self.for_instance( binding, field_name )
63
+ def self.for_instance(binding, field_name)
64
64
  metaclass = class << binding.object; self; end
65
65
  for_class( metaclass, binding, field_name )
66
66
  end
@@ -69,7 +69,7 @@ module StateFu
69
69
  # also ensures the persister class method :prepare_field has been called
70
70
  # once for the given class & field name so the field can be set up; eg an
71
71
  # attr_accessor or a before_save hook defined
72
- def self.for( binding )
72
+ def self.for(binding)
73
73
  field_name = binding.field_name.to_sym
74
74
  if binding.singleton?
75
75
  for_instance( binding, field_name )
@@ -95,21 +95,21 @@ module StateFu
95
95
  # checks to see if the field_name for persistence is a
96
96
  # RelaxDB attribute.
97
97
  # Safe to use (skipped) if RelaxDB is not included.
98
- def self.relaxdb_document_property?( klass, field_name )
98
+ def self.relaxdb_document_property?(klass, field_name)
99
99
  Object.const_defined?('RelaxDB') &&
100
100
  klass.ancestors.include?( ::RelaxDB::Document ) &&
101
- klass.properties.map(&:to_s).include?( field_name.to_s )
101
+ klass.properties.map(&:to_s).include?(field_name.to_s)
102
102
  end
103
103
 
104
104
  # checks to see if the field_name for persistence is an
105
105
  # ActiveRecord column.
106
106
  # Safe to use (skipped) if ActiveRecord is not included.
107
- def self.active_record_column?( klass, field_name )
107
+ def self.active_record_column?(klass, field_name)
108
108
  Object.const_defined?("ActiveRecord") &&
109
109
  ::ActiveRecord.const_defined?("Base") &&
110
- klass.ancestors.include?( ::ActiveRecord::Base ) &&
110
+ klass.ancestors.include?(::ActiveRecord::Base) &&
111
111
  klass.table_exists? &&
112
- klass.columns.map(&:name).include?( field_name.to_s )
112
+ klass.columns.map(&:name).include?(field_name.to_s)
113
113
  end
114
114
 
115
115
  end
data/lib/state-fu.rb CHANGED
@@ -16,15 +16,13 @@
16
16
  #
17
17
  # It is also delightfully elegant and easy to use for simple things.
18
18
 
19
-
20
- require 'rubygems'
21
-
22
19
  [ 'support/core_ext',
23
20
  'support/logger',
24
21
  'support/applicable',
25
22
  'support/arrays',
26
23
  'support/methodical',
27
24
  'support/has_options',
25
+ 'support/vizier',
28
26
  'support/plotter',
29
27
  'support/exceptions',
30
28
  'executioner',
@@ -1,5 +1,3 @@
1
- require 'rubygems'
2
-
3
1
  # if ActiveSupport is absent, install a very small subset of it for
4
2
  # some convenience methods
5
3
  unless Object.const_defined?('ActiveSupport') #:nodoc
@@ -1,4 +1,3 @@
1
- require 'vizier'
2
1
  require 'tempfile'
3
2
 
4
3
  module StateFu
@@ -8,39 +8,48 @@ unless Object.const_defined?('STATE_FU_PLUGIN_PATH')
8
8
  STATE_FU_PLUGIN_PATH = Object.const_defined?('RAILS_ROOT') ? File.join( RAILS_ROOT, '/vendor/plugins/state-fu' ) : STATE_FU_APP_PATH
9
9
  end
10
10
 
11
- namespace :spec do
12
- def find_last_modified_spec
13
- require 'find'
14
- specs = []
15
- Find.find( File.expand_path(File.join(STATE_FU_APP_PATH,'spec'))) do |f|
16
- next unless f !~ /\.#/ && f =~ /_spec.rb$/
17
- specs << f
11
+ begin
12
+ require 'rake'
13
+ require 'spec'
14
+ require 'spec/rake/spectask'
15
+
16
+ namespace :spec do
17
+ def find_last_modified_spec
18
+ require 'find'
19
+ specs = []
20
+ Find.find( File.expand_path(File.join(STATE_FU_APP_PATH,'spec'))) do |f|
21
+ next unless f !~ /\.#/ && f =~ /_spec.rb$/
22
+ specs << f
23
+ end
24
+ spec = specs.sort_by { |spec| File.stat( spec ).mtime }.last
18
25
  end
19
- spec = specs.sort_by { |spec| File.stat( spec ).mtime }.last
20
- end
21
26
 
22
- desc "runs the last modified spec; L=n runs only that line"
23
- Spec::Rake::SpecTask.new(:last) do |t|
24
- specfile = find_last_modified_spec || return
25
- t.verbose = true
26
- t.spec_opts = ["-c","-b","-u"]
27
- if ENV['L']
28
- t.spec_opts += ["-l", ENV["L"],"-f", "specdoc"]
29
- else
30
- t.spec_opts += ["-f", "profile"]
27
+ desc "runs the last modified spec; L=n runs only that line"
28
+ Spec::Rake::SpecTask.new(:last) do |t|
29
+ specfile = find_last_modified_spec || return
30
+ t.verbose = true
31
+ t.spec_opts = ["-c","-b","-u"]
32
+ if ENV['L']
33
+ t.spec_opts += ["-l", ENV["L"],"-f", "specdoc"]
34
+ else
35
+ t.spec_opts += ["-f", "profile"]
36
+ end
37
+ t.spec_files = FileList[specfile]
31
38
  end
32
- t.spec_files = FileList[specfile]
33
- end
34
39
 
35
- desc "runs all specs, or those which last failed"
36
- Spec::Rake::SpecTask.new(:faily) do |t|
37
- specfile = find_last_modified_spec || return
38
- faily = 'spec.fail'
39
- t.verbose = true
40
- t.spec_opts = ["-f","failing_examples:#{faily}", "-f","n","-c","-b","-u"]
41
- if File.exists?(faily) && File.read(faily).split("\n")[0] != ""
42
- t.spec_opts << ["-e",faily]
40
+ desc "runs all specs, or those which last failed"
41
+ Spec::Rake::SpecTask.new(:faily) do |t|
42
+ specfile = find_last_modified_spec || return
43
+ faily = 'spec.fail'
44
+ t.verbose = true
45
+ t.spec_opts = ["-f","failing_examples:#{faily}", "-f","n","-c","-b","-u"]
46
+ if File.exists?(faily) && File.read(faily).split("\n")[0] != ""
47
+ t.spec_opts << ["-e",faily]
48
+ end
43
49
  end
44
50
  end
45
51
 
52
+ rescue LoadError
53
+ # fail quietly if rspec is not installed
46
54
  end
55
+
data/lib/transition.rb CHANGED
@@ -256,6 +256,10 @@ module StateFu
256
256
  alias_method :original_state, :origin
257
257
  alias_method :initial_state, :origin
258
258
  alias_method :from, :origin
259
+
260
+ def cycle?
261
+ origin == target
262
+ end
259
263
 
260
264
  # an accepted transition == true
261
265
  # an unaccepted transition == false
@@ -127,11 +127,11 @@ module StateFu
127
127
  end
128
128
 
129
129
  def events
130
- map {|t| t.event }
130
+ map {|t| t.event }.extend EventArray
131
131
  end
132
132
 
133
133
  def targets
134
- map {|t| t.target }
134
+ map {|t| t.target }.extend StateArray
135
135
  end
136
136
 
137
137
  private
@@ -0,0 +1,46 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe "defining an alias for the default machine" do
4
+ describe "with machine(:as => :status)" do
5
+ before do
6
+ make_pristine_class('Klass')
7
+ Klass.machine :as => :status do
8
+ state :active
9
+ end
10
+ @obj = Klass.new
11
+ end
12
+
13
+ it "should not prevent normal access through #state_fu" do
14
+ @obj.state_fu.machine.should == Klass.machine
15
+ end
16
+
17
+ it "should not affect the internal name of the machine" do
18
+ @obj.status.method_name.should == :default
19
+ end
20
+
21
+ it "should let you access the machine through #status" do
22
+ @obj.status.should be_kind_of(StateFu::Binding)
23
+ @obj.status.machine.should == Klass.machine
24
+ @obj.status.current_state.should == :active
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ describe "defining an alias for a default singleton machine" do
31
+ describe "with #bind! :default, :as => :alias" do
32
+ before do
33
+ make_pristine_class('Klass')
34
+ @machine = StateFu::Machine.new do
35
+ state :exemplary
36
+ end
37
+ @obj = Klass.new
38
+ @machine.bind!( @obj, :default, :as => :example)
39
+ end
40
+
41
+ it "should work too" do
42
+ @obj.example.machine.should == @machine
43
+ end
44
+ end
45
+ end
46
+
@@ -5,7 +5,7 @@ describe "singleton machines" do
5
5
  make_pristine_class('Klass')
6
6
  @m = StateFu::Machine.new do
7
7
  state :a do
8
- event :beatify, :transitions_to => :b
8
+ event :bify, :transitions_to => :b
9
9
  end
10
10
  end
11
11
  @m.events.length.should == 1
@@ -20,9 +20,22 @@ describe "singleton machines" do
20
20
  @obj.my_binding.object.should == @obj
21
21
  end
22
22
 
23
- it "should have event methods defined" do
24
- %w/beatify can_beatify? beatify!/.each do |method_name|
23
+ it "should have methods defined on the binding by default" do
24
+ %w/bify can_bify? bify!/.each do |method_name|
25
25
  @obj.my_binding.should respond_to(method_name)
26
+ end
27
+ end
28
+
29
+ it "should not have methods defined on the instance by default" do
30
+ %w/bify can_bify? bify!/.each do |method_name|
31
+ @obj.should_not respond_to(method_name)
32
+ end
33
+ end
34
+
35
+
36
+ it "should have methods defined on the instance if bound with :define_methods => true" do
37
+ @m.bind!( @obj, :my_binding, :define_methods => true)
38
+ %w/bify can_bify? bify!/.each do |method_name|
26
39
  @obj.should respond_to(method_name)
27
40
  end
28
41
  end
@@ -30,7 +43,7 @@ describe "singleton machines" do
30
43
  it "should transition" do
31
44
  @b = @obj.my_binding
32
45
  @b.current_state.should == :a
33
- t = @obj.beatify!
46
+ t = @obj.my_binding.bify!
34
47
  t.should be_kind_of(StateFu::Transition)
35
48
  t.should be_accepted
36
49
  @b.current_state.should == :b
@@ -0,0 +1,114 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe "instance methods defined for a class's machine," do
4
+ before do
5
+ make_pristine_class('Klass')
6
+ end
7
+
8
+ describe "for the default machine" do
9
+ it "should define methods for states and events" do
10
+ Klass.machine do
11
+ event :go, :from => :a, :to => :b
12
+ end
13
+ instance = Klass.new
14
+ instance.state_fu!
15
+ instance.should respond_to(:a?)
16
+ instance.should respond_to(:can_go?)
17
+ end
18
+
19
+ it "should not define methods given :define_methods => false" do
20
+ Klass.machine :define_methods => false do
21
+ event :go, :from => :a, :to => :b
22
+ end
23
+ instance = Klass.new
24
+ instance.state_fu!
25
+ instance.should_not respond_to(:a?)
26
+ instance.should_not respond_to(:can_go?)
27
+ end
28
+ end
29
+
30
+ describe "for other machines" do
31
+ it "should not define methods" do
32
+ Klass.machine :other do
33
+ event :go, :from => :a, :to => :b
34
+ end
35
+ instance = Klass.new
36
+ instance.state_fu!
37
+ instance.should_not respond_to(:a?)
38
+ instance.should_not respond_to(:can_go?)
39
+ end
40
+
41
+ it "should define methods given :define_methods => true" do
42
+ Klass.machine :define_methods => true do
43
+ event :go, :from => :a, :to => :b
44
+ end
45
+ instance = Klass.new
46
+ instance.state_fu!
47
+ instance.should respond_to(:a?)
48
+ instance.should respond_to(:can_go?)
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ describe "instance methods when you #bind! a machine" do
55
+ before do
56
+ make_pristine_class('Klass')
57
+ @machine = StateFu::Machine.new do
58
+ state :hot
59
+ state :cold
60
+ end
61
+ end
62
+
63
+ describe "as the default machine," do
64
+ describe "the default behaviour" do
65
+ before do
66
+ @machine.bind! Klass, :default, :define_methods => true
67
+ end
68
+
69
+ it "defines methods" do
70
+ instance = Klass.new
71
+ instance.state_fu!
72
+ instance.should respond_to(:hot?)
73
+ end
74
+ end
75
+
76
+ describe "when it is bound with :define_methods => false" do
77
+ before do
78
+ @machine.bind! Klass, :default, :define_methods => false
79
+ end
80
+
81
+ it "should not define methods" do
82
+ instance = Klass.new
83
+ instance.state_fu!
84
+ instance.should_not respond_to(:hot?)
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "as another machine," do
90
+ describe "the default behaviour" do
91
+ before do
92
+ @machine.bind! Klass, :temperature
93
+ end
94
+
95
+ it "should not define methods" do
96
+ instance = Klass.new
97
+ instance.state_fu!
98
+ instance.should_not respond_to(:hot?)
99
+ end
100
+ end
101
+
102
+ describe "when it is bound with :define_methods => true" do
103
+ before do
104
+ @machine.bind! Klass, :temperature, :define_methods => true
105
+ end
106
+
107
+ it "should define methods" do
108
+ instance = Klass.new
109
+ instance.state_fu!
110
+ instance.should respond_to(:hot?)
111
+ end
112
+ end
113
+ end
114
+ end
data/spec/spec_helper.rb CHANGED
@@ -4,7 +4,7 @@ thisdir = File.expand_path(File.dirname(__FILE__))
4
4
  # ensure we require state-fu from lib, not gems
5
5
  $LOAD_PATH.unshift( "#{thisdir}/../lib" )
6
6
  require 'state-fu'
7
- require 'no_stdout'
7
+ require 'support/no_stdout'
8
8
  require 'fileutils'
9
9
  require 'rubygems'
10
10
  require 'spec'