ultra_marathon 0.1.0 → 0.1.1

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.
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