ultra_marathon 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d4509883d5029d7c4a4a1dae968fce358849c10
4
- data.tar.gz: 10319093704148baaa01957b3d0016a1dcb14fd7
3
+ metadata.gz: 4dc515ceea5248b2ac05129ad6b2f5d074742819
4
+ data.tar.gz: e68e4458184d953024a5efe23083dfc4a3f9ba8c
5
5
  SHA512:
6
- metadata.gz: 48e6c87b833a453bc4933847a612678a8e7f239d2f5642ef393a4ebdf05e1d0e330c0d57966ea27f2f6dbe0ac2041196e548d1ade29412e0a586ad81e5863c59
7
- data.tar.gz: 4fab0f2cc7c61bc3f615459babc953c6fba3b9878ca6734a28efd791874d21eb7b0fe2ccf54c723476a7a78843a227b5288174175605efb6002f29ed58a67979
6
+ metadata.gz: 9c32534cc602929cfcc7b0d98d47f868e8838adc1de117ffe31a2f73e64bcd9b6679cf09af40daf8ec5e2b4bd9da86106c4fa05f02e8a350e536d606f4ef9d19
7
+ data.tar.gz: 932ebf6722c3e7fafe391b0e725eb2d2ef280b9187ccc365bf76ca39bc78d2100e5db415caa183de646ed2d9967f9a8c4b290b87203295af45666c299dd1bea1
data/README.md CHANGED
@@ -18,7 +18,7 @@ running complex jobs. It is best inheirited to fully customize.
18
18
  A simple DSL, currently consisting of only the `run` command, are used to
19
19
  specify independent chunks of work. The first argument is the name of the run
20
20
  block. Omitted, this defaults to ':main', though names must be unique within a
21
- given Runner so for a runner with N run blocks, N - 1 must be manually named.
21
+ given Runner. E.g. for a runner with N run blocks, N - 1 must be manually named.
22
22
 
23
23
  ```ruby
24
24
  class MailRunner < UltraMarathon::AbstractRunner
@@ -29,12 +29,19 @@ class MailRunner < UltraMarathon::AbstractRunner
29
29
  end
30
30
 
31
31
  # :eat run block
32
+ # Must be named because there is already a :main block (one without
33
+ # a name explicitly defined)
32
34
  run :eat do
33
35
  add_butter
34
36
  add_syrup
35
37
  eat!
36
38
  end
37
39
 
40
+ # Will throw an error, since the first runner is implicitly named :main
41
+ run :main do
42
+ puts 'nope nope nope!'
43
+ end
44
+
38
45
  # Omitted for brevity
39
46
  def add_butter; end
40
47
  def add_syrup; end
@@ -137,6 +144,19 @@ class MercurialRunner < UltraMarathon::AbstractRunner
137
144
  end
138
145
  ```
139
146
 
147
+ ### Instrumentation
148
+
149
+ The entire `run!` is instrumented and logged automatically. Additionally,
150
+ individual run blocks are instrumented and logged by default.
151
+
152
+ You can also choose to not instrument a block:
153
+
154
+ ```ruby
155
+ run :embarrassingly_slowly, instrument: false do
156
+ sleep(rand(10))
157
+ end
158
+ ```
159
+
140
160
  ### Success, Failure, and Reseting
141
161
 
142
162
  If any part of a runner fails, either by raising an error or explicitly setting
@@ -144,8 +164,10 @@ If any part of a runner fails, either by raising an error or explicitly setting
144
164
  which rely on an unsuccessful run block will also be considered failed.
145
165
 
146
166
  A failed runner can be reset, which essentially changes the failed runners to
147
- being unrun and returns the success flag to true. It will then execute any
148
- `on_reset` callbacks before returning itself.
167
+ being unrun and returns the success flag to true. Runners that have been
168
+ successfully run _will not_ be rerun, though any failed dependencies will.
169
+
170
+ The runner will then execute any `on_reset` callbacks before returning itself.
149
171
 
150
172
  ```ruby
151
173
  class WatRunner < UltraMarathon::AbstractRunner
@@ -24,7 +24,7 @@ module UltraMarathon
24
24
  begin
25
25
  self.success = true
26
26
  invoke_before_run_callbacks
27
- instrument { run_unrun_sub_runners }
27
+ instrument(:run_unrun_sub_runners) { run_unrun_sub_runners }
28
28
  self.success = failed_sub_runners.empty?
29
29
  rescue StandardError => error
30
30
  invoke_on_error_callbacks(error)
@@ -180,12 +180,13 @@ module UltraMarathon
180
180
  end
181
181
 
182
182
  def summary
183
+ run_instrumentation = instrumentations[:run_unrun_sub_runners]
183
184
  """
184
185
 
185
186
  Status: #{status}
186
- Start Time: #{formatted_start_time}
187
- End Time: #{formatted_end_time}
188
- Total Time: #{formatted_total_time}
187
+ Run Start Time: #{run_instrumentation.formatted_start_time}
188
+ End Time: #{run_instrumentation.formatted_end_time}
189
+ Total Time: #{run_instrumentation.formatted_total_time}
189
190
 
190
191
  Successful SubRunners: #{successful_sub_runners.size}
191
192
  Failed SubRunners: #{failed_sub_runners.size}
@@ -1,49 +1,25 @@
1
+ require 'ultra_marathon/instrumentation/profile'
2
+
1
3
  module UltraMarathon
2
4
  module Instrumentation
3
5
  TIME_FORMAT = "%02d:%02d:%02d"
4
- attr_reader :start_time, :end_time
5
6
 
6
7
  ## Public Instance Methods
7
8
 
8
- # returns the total time, in seconds
9
- def total_time
10
- (end_time - start_time).to_i
11
- end
12
-
13
- def formatted_total_time
14
- duration = total_time
15
- seconds = (duration % 60).floor
16
- minutes = (duration / 60).floor
17
- hours = (duration / 3600).floor
18
- sprintf(TIME_FORMAT, hours, minutes, seconds)
19
- end
20
-
21
- def formatted_start_time
22
- format_time(start_time)
23
- end
24
-
25
- def formatted_end_time
26
- format_time(end_time)
9
+ def instrumentations
10
+ @instrumentations ||= Hash.new
27
11
  end
28
12
 
29
13
  private
30
14
 
31
15
  ## Private Instance Methods
32
16
 
33
- def format_time(time)
34
- sprintf(TIME_FORMAT, time.hour, time.min, time.sec)
35
- end
36
-
37
17
  # Instruments given block, setting its start time and end time
38
18
  # Returns the result of the block
39
- def instrument(&block)
40
- @start_time = Time.now
41
- begin
42
- return_value = yield
43
- ensure
44
- @end_time = Time.now
45
- end
46
- return_value
19
+ def instrument(name, &block)
20
+ profile = Profile.new(name, &block)
21
+ instrumentations[name] = profile
22
+ profile.call
47
23
  end
48
24
  end
49
25
  end
@@ -0,0 +1,51 @@
1
+ module UltraMarathon
2
+ module Instrumentation
3
+ class Profile
4
+ attr_reader :name, :instrument_block, :start_time, :end_time
5
+
6
+ ## Public Instance Methods
7
+
8
+ def initialize(name, &block)
9
+ @name = name
10
+ @instrument_block = block
11
+ end
12
+
13
+ def call
14
+ @start_time = Time.now
15
+ begin
16
+ return_value = instrument_block.call
17
+ ensure
18
+ @end_time = Time.now
19
+ end
20
+ return_value
21
+ end
22
+
23
+ # returns the total time, in seconds
24
+ def total_time
25
+ (end_time - start_time).to_i
26
+ end
27
+
28
+ def formatted_total_time
29
+ duration = total_time
30
+ seconds = (duration % 60).floor
31
+ minutes = (duration / 60).floor
32
+ hours = (duration / 3600).floor
33
+ sprintf(TIME_FORMAT, hours, minutes, seconds)
34
+ end
35
+
36
+ def formatted_start_time
37
+ format_time(start_time)
38
+ end
39
+
40
+ def formatted_end_time
41
+ format_time(end_time)
42
+ end
43
+
44
+ ## Private Instance Methods
45
+
46
+ def format_time(time)
47
+ sprintf(TIME_FORMAT, time.hour, time.min, time.sec)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,11 +1,13 @@
1
1
  require 'set'
2
2
  require 'active_support/core_ext/proc'
3
3
  require 'ultra_marathon/callbacks'
4
+ require 'ultra_marathon/instrumentation'
4
5
  require 'ultra_marathon/logging'
5
6
 
6
7
  module UltraMarathon
7
8
  class SubRunner
8
9
  include Callbacks
10
+ include Instrumentation
9
11
  include Logging
10
12
  attr_accessor :run_block, :success
11
13
  attr_reader :sub_context, :options, :name
@@ -22,18 +24,32 @@ module UltraMarathon
22
24
  # other class, but do other things (like log) in the context of this one.
23
25
  def initialize(options, run_block)
24
26
  @name = options[:name]
25
- @options = options
27
+ @options = {
28
+ instrument: true
29
+ }.merge(options)
26
30
  @sub_context = SubContext.new(options[:context], run_block)
27
31
  end
28
32
 
29
33
  def run!
30
- begin
31
- self.success = true
32
- run_sub_context
33
- rescue StandardError => error
34
- invoke_on_error_callbacks(error)
35
- ensure
36
- invoke_after_run_callbacks
34
+ instrument(:run) do
35
+ begin
36
+ self.success = true
37
+ run_sub_context
38
+ rescue StandardError => error
39
+ invoke_on_error_callbacks(error)
40
+ ensure
41
+ invoke_after_run_callbacks
42
+ end
43
+ end
44
+ log_instrumentation
45
+ end
46
+
47
+ def log_instrumentation
48
+ if options[:instrument]
49
+ run_profile = instrumentations[:run]
50
+ logger.info """
51
+ Total Time: #{run_profile.formatted_total_time}
52
+ """
37
53
  end
38
54
  end
39
55
 
@@ -76,9 +92,14 @@ module UltraMarathon
76
92
 
77
93
  def initialize(context, run_block)
78
94
  @context = context
95
+ @run_block = run_block
79
96
  # Ruby cannot marshal procs or lambdas, so we need to define a method.
80
97
  # Binding to self allows us to intercept logging calls.
81
- define_singleton_method :call, &run_block.bind(self)
98
+ define_singleton_method(:call, &bound_block)
99
+ end
100
+
101
+ def bound_block
102
+ run_block.bind(self)
82
103
  end
83
104
 
84
105
  # If the original context responds, including private methods,
@@ -2,7 +2,7 @@ module UltraMarathon
2
2
  class Version
3
3
  MAJOR = 0 unless defined? MAJOR
4
4
  MINOR = 1 unless defined? MINOR
5
- PATCH = 0 unless defined? PATCH
5
+ PATCH = 1 unless defined? PATCH
6
6
  PRE = nil unless defined? PRE
7
7
 
8
8
  class << self
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ describe UltraMarathon::Instrumentation::Profile do
3
+ let(:start_time) { Time.local(1991, 1, 31, 15, 15, 00) }
4
+ let(:end_time) { Time.local(1991, 1, 31, 16, 00, 20) }
5
+ let(:run_block) do
6
+ # This is going to be evaluated in context of the instance
7
+ # so we need to wrap in an IIF to access `end_time`
8
+ Proc.new do |end_time|
9
+ Proc.new do
10
+ Timecop.travel(end_time)
11
+ 'Bubbles'
12
+ end
13
+ end.call(end_time)
14
+ end
15
+
16
+ let(:profile) { described_class.new(:speedy, &run_block) }
17
+
18
+ subject(:run) { profile.call }
19
+
20
+ before(:each) { Timecop.freeze(start_time) }
21
+ after(:each) { Timecop.return }
22
+
23
+ it 'should set its name' do
24
+ profile.name.should be :speedy
25
+ end
26
+
27
+ describe '#call' do
28
+ it 'should return the result of the block' do
29
+ run.should eq 'Bubbles'
30
+ end
31
+
32
+ it 'should set the start_time' do
33
+ run
34
+ profile.start_time.should eq start_time
35
+ end
36
+
37
+ it 'should set the end_time' do
38
+ run
39
+ profile.end_time.to_i.should eq end_time.to_i
40
+ end
41
+ end
42
+
43
+ describe 'total_time' do
44
+ before(:each) { run }
45
+
46
+ it 'should return the total seconds elapsed' do
47
+ profile.total_time.should eq 2720
48
+ end
49
+ end
50
+
51
+ describe '#formatted_total_time' do
52
+ before(:each) { run }
53
+
54
+ it 'should return the total time, formatted' do
55
+ profile.formatted_total_time.should eq '00:45:20'
56
+ end
57
+ end
58
+ end
@@ -6,65 +6,26 @@ describe UltraMarathon::Instrumentation do
6
6
  include UltraMarathon::Instrumentation
7
7
 
8
8
  def run(&block)
9
- instrument { block.call }
9
+ instrument(:run) { block.call }
10
10
  end
11
11
  end
12
12
  end
13
13
 
14
14
  let(:test_instance) { test_class.new }
15
- let(:start_time) { Time.local(1991, 1, 31, 15, 15, 00) }
16
- let(:end_time) { Time.local(1991, 1, 31, 16, 00, 20) }
17
- let(:run_block) do
18
- # This is going to be evaluated in context of the instance
19
- # so we need to wrap in an IIF to access `end_time`
20
- Proc.new do |end_time|
21
- Proc.new do
22
- Timecop.travel(end_time)
23
- end
24
- end.call(end_time)
25
- end
26
15
 
27
16
  subject(:run) { test_instance.run &run_block }
28
17
 
29
- before(:each) { Timecop.freeze(start_time) }
30
- after(:each) { Timecop.return }
31
-
32
18
  describe '#instrument' do
19
+ let(:run_block) { Proc.new { 'Bubbles!' } }
33
20
 
34
- describe 'method signature' do
35
- let(:run_block) { Proc.new { 'Bubbles!' } }
36
-
37
- it 'should return the result of the passed in block' do
38
- run.should eq 'Bubbles!'
39
- end
21
+ it 'should return the result of the passed in block' do
22
+ run.should eq 'Bubbles!'
40
23
  end
41
24
 
42
- describe 'setting instance variables' do
43
- before(:each) { run }
44
-
45
- it 'should set the start_time' do
46
- test_instance.start_time.should eq start_time
47
- end
48
-
49
- it 'should set the end_time' do
50
- test_instance.end_time.to_i.should eq end_time.to_i
51
- end
52
- end
53
- end
54
-
55
- describe 'total_time' do
56
- before(:each) { run }
57
-
58
- it 'should return the total seconds elapsed' do
59
- test_instance.total_time.should eq 2720
60
- end
61
- end
62
-
63
- describe '#formatted_total_time' do
64
- before(:each) { run }
65
-
66
- it 'should return the total time, formatted' do
67
- test_instance.formatted_total_time.should eq '00:45:20'
25
+ it 'should add the instrumentation information to the #instrumentations hash' do
26
+ run
27
+ profile = test_instance.instrumentations[:run]
28
+ profile.should be_an UltraMarathon::Instrumentation::Profile
68
29
  end
69
30
  end
70
31
  end
@@ -50,5 +50,22 @@ describe UltraMarathon::SubRunner do
50
50
  test_instance.logger.contents.should include 'Draws those who are willing, drags those who are not.'
51
51
  end
52
52
  end
53
+
54
+ describe 'instrumentation' do
55
+ it 'should log the total time' do
56
+ subject
57
+ test_instance.logger.contents.should include 'Total Time:'
58
+ end
59
+
60
+ describe 'when instrument: false is set' do
61
+ let(:options) do
62
+ { context: context, name: name, instrument: false }
63
+ end
64
+
65
+ it 'should not log total time' do
66
+ test_instance.logger.contents.should_not include 'Total Time:'
67
+ end
68
+ end
69
+ end
53
70
  end
54
71
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ultra_marathon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Maddox
@@ -22,6 +22,7 @@ files:
22
22
  - lib/ultra_marathon/abstract_runner.rb
23
23
  - lib/ultra_marathon/callbacks.rb
24
24
  - lib/ultra_marathon/instrumentation.rb
25
+ - lib/ultra_marathon/instrumentation/profile.rb
25
26
  - lib/ultra_marathon/logger.rb
26
27
  - lib/ultra_marathon/logging.rb
27
28
  - lib/ultra_marathon/store.rb
@@ -32,6 +33,7 @@ files:
32
33
  - spec/support/test_helpers.rb
33
34
  - spec/ultra_marathon/abstract_runner_spec.rb
34
35
  - spec/ultra_marathon/callbacks_spec.rb
36
+ - spec/ultra_marathon/instrumentation/profile_spec.rb
35
37
  - spec/ultra_marathon/instrumentation_spec.rb
36
38
  - spec/ultra_marathon/logging_spec.rb
37
39
  - spec/ultra_marathon/store_spec.rb
@@ -67,6 +69,7 @@ test_files:
67
69
  - spec/support/test_helpers.rb
68
70
  - spec/ultra_marathon/abstract_runner_spec.rb
69
71
  - spec/ultra_marathon/callbacks_spec.rb
72
+ - spec/ultra_marathon/instrumentation/profile_spec.rb
70
73
  - spec/ultra_marathon/instrumentation_spec.rb
71
74
  - spec/ultra_marathon/logging_spec.rb
72
75
  - spec/ultra_marathon/store_spec.rb