html-pipeline 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.0.11
4
+
5
+ * add instrumentation support. readme cleanup mtodd #45
6
+
3
7
  ## 0.0.10
4
8
 
5
9
  * add bin/html-pipeline util indirect #44
data/README.md CHANGED
@@ -53,9 +53,7 @@ pipeline = HTML::Pipeline.new [
53
53
  result = pipeline.call <<-CODE
54
54
  This is *great*:
55
55
 
56
- ``` ruby
57
- some_code(:first)
58
- ```
56
+ some_code(:first)
59
57
 
60
58
  CODE
61
59
  result[:output].to_s
@@ -178,7 +176,7 @@ require 'uri'
178
176
  class RootRelativeFilter < HTML::Pipeline::Filter
179
177
 
180
178
  def call
181
- doc.search("img").each do |img|
179
+ doc.search("img").each do |img|
182
180
  next if img['src'].nil?
183
181
  src = img['src'].strip
184
182
  if src.start_with? '/'
@@ -197,6 +195,44 @@ Now this filter can be used in a pipeline:
197
195
  Pipeline.new [ RootRelativeFilter ], { :base_url => 'http://somehost.com' }
198
196
  ```
199
197
 
198
+ ## Instrumenting
199
+
200
+ To instrument each filter and a full pipeline call, set an
201
+ [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html)
202
+ service object on a pipeline object. New pipeline objects will default to the
203
+ `HTML::Pipeline.default_instrumentation_service` object.
204
+
205
+ ``` ruby
206
+ # the AS::Notifications-compatible service object
207
+ service = ActiveSupport::Notifications
208
+
209
+ # instrument a specific pipeline
210
+ pipeline = HTML::Pipeline.new [MarkdownFilter], context
211
+ pipeline.instrumentation_service = service
212
+
213
+ # or instrument all new pipelines
214
+ HTML::Pipeline.default_instrumentation_service = service
215
+ ```
216
+
217
+ Filters are instrumented when they are run through the pipeline. A
218
+ `call_filter.html_pipeline` event is published once the filter finishes. The
219
+ `payload` should include the `filter` name. Each filter will trigger its own
220
+ instrumentation call.
221
+
222
+ ``` ruby
223
+ service.subscribe "call_filter.html_pipeline" do |event, start, ending, transaction_id, payload|
224
+ payload[:filter] #=> "MarkdownFilter"
225
+ end
226
+ ```
227
+
228
+ The full pipeline is also instrumented:
229
+
230
+ ``` ruby
231
+ service.subscribe "call_pipeline.html_pipeline" do |event, start, ending, transaction_id, payload|
232
+ payload[:filters] #=> ["MarkdownFilter"]
233
+ end
234
+ ```
235
+
200
236
  ## Development
201
237
 
202
238
  To see what has changed in recent versions, see the [CHANGELOG](https://github.com/jch/html-pipeline/blob/master/CHANGELOG.md).
data/lib/html/pipeline.rb CHANGED
@@ -61,11 +61,21 @@ module HTML
61
61
  # Public: Returns an Array of Filter objects for this Pipeline.
62
62
  attr_reader :filters
63
63
 
64
+ # Public: Instrumentation service for the pipeline.
65
+ # Set an ActiveSupport::Notifications compatible object to enable.
66
+ attr_accessor :instrumentation_service
67
+
68
+ class << self
69
+ # Public: Default instrumentation service for new pipeline objects.
70
+ attr_accessor :default_instrumentation_service
71
+ end
72
+
64
73
  def initialize(filters, default_context = {}, result_class = nil)
65
74
  raise ArgumentError, "default_context cannot be nil" if default_context.nil?
66
75
  @filters = filters.flatten.freeze
67
76
  @default_context = default_context.freeze
68
77
  @result_class = result_class || Hash
78
+ @instrumentation_service = self.class.default_instrumentation_service
69
79
  end
70
80
 
71
81
  # Apply all filters in the pipeline to the given HTML.
@@ -84,10 +94,37 @@ module HTML
84
94
  context = @default_context.merge(context)
85
95
  context = context.freeze
86
96
  result ||= @result_class.new
87
- result[:output] = @filters.inject(html) { |doc, filter| filter.call(doc, context, result) }
97
+ instrument "call_pipeline.html_pipeline", :filters => @filters.map(&:name) do
98
+ result[:output] =
99
+ @filters.inject(html) do |doc, filter|
100
+ perform_filter(filter, doc, context, result)
101
+ end
102
+ end
88
103
  result
89
104
  end
90
105
 
106
+ # Internal: Applies a specific filter to the supplied doc.
107
+ #
108
+ # The filter is instrumented.
109
+ #
110
+ # Returns the result of the filter.
111
+ def perform_filter(filter, doc, context, result)
112
+ instrument "call_filter.html_pipeline", :filter => filter.name do
113
+ filter.call(doc, context, result)
114
+ end
115
+ end
116
+
117
+ # Internal: if the `instrumentation_service` object is set, instruments the
118
+ # block, otherwise the block is ran without instrumentation.
119
+ #
120
+ # Returns the result of the provided block.
121
+ def instrument(event, payload = nil)
122
+ return yield unless instrumentation_service
123
+ instrumentation_service.instrument event, payload do
124
+ yield
125
+ end
126
+ end
127
+
91
128
  # Like call but guarantee the value returned is a DocumentFragment.
92
129
  # Pipelines may return a DocumentFragment or a String. Callers that need a
93
130
  # DocumentFragment should use this method.
@@ -1,5 +1,5 @@
1
1
  module HTML
2
2
  class Pipeline
3
- VERSION = "0.0.10"
3
+ VERSION = "0.0.11"
4
4
  end
5
5
  end
@@ -0,0 +1,15 @@
1
+ class MockedInstrumentationService
2
+ attr_reader :events
3
+ def initialize(event = nil, events = [])
4
+ @events = events
5
+ subscribe event
6
+ end
7
+ def instrument(event, payload = nil)
8
+ res = yield
9
+ events << [event, payload, res] if @subscribe == event
10
+ res
11
+ end
12
+ def subscribe(event)
13
+ @subscribe = event
14
+ end
15
+ end
@@ -0,0 +1,52 @@
1
+ require "test_helper"
2
+ require "helpers/mocked_instrumentation_service"
3
+
4
+ class HTML::PipelineTest < Test::Unit::TestCase
5
+ Pipeline = HTML::Pipeline
6
+ class TestFilter
7
+ def self.call(input, context, result)
8
+ input
9
+ end
10
+ end
11
+
12
+ def setup
13
+ @context = {}
14
+ @result_class = Hash
15
+ @pipeline = Pipeline.new [TestFilter], @context, @result_class
16
+ end
17
+
18
+ def test_filter_instrumentation
19
+ service = MockedInstrumentationService.new
20
+ service.subscribe "call_filter.html_pipeline"
21
+ @pipeline.instrumentation_service = service
22
+ filter("hello")
23
+ event, payload, res = service.events.pop
24
+ assert event, "event expected"
25
+ assert_equal "call_filter.html_pipeline", event
26
+ assert_equal TestFilter.name, payload[:filter]
27
+ end
28
+
29
+ def test_pipeline_instrumentation
30
+ service = MockedInstrumentationService.new
31
+ service.subscribe "call_pipeline.html_pipeline"
32
+ @pipeline.instrumentation_service = service
33
+ filter("hello")
34
+ event, payload, res = service.events.pop
35
+ assert event, "event expected"
36
+ assert_equal "call_pipeline.html_pipeline", event
37
+ assert_equal @pipeline.filters.map(&:name), payload[:filters]
38
+ end
39
+
40
+ def test_default_instrumentation_service
41
+ service = 'default'
42
+ Pipeline.default_instrumentation_service = service
43
+ pipeline = Pipeline.new [], @context, @result_class
44
+ assert_equal service, pipeline.instrumentation_service
45
+ ensure
46
+ Pipeline.default_instrumentation_service = nil
47
+ end
48
+
49
+ def filter(input)
50
+ @pipeline.call(input)
51
+ end
52
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-03-21 00:00:00.000000000 Z
13
+ date: 2013-03-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: gemoji
@@ -176,6 +176,7 @@ files:
176
176
  - lib/html/pipeline/textile_filter.rb
177
177
  - lib/html/pipeline/toc_filter.rb
178
178
  - lib/html/pipeline/version.rb
179
+ - test/helpers/mocked_instrumentation_service.rb
179
180
  - test/html/pipeline/absolute_source_filter_test.rb
180
181
  - test/html/pipeline/autolink_filter_test.rb
181
182
  - test/html/pipeline/camo_filter_test.rb
@@ -186,6 +187,7 @@ files:
186
187
  - test/html/pipeline/plain_text_input_filter_test.rb
187
188
  - test/html/pipeline/sanitization_filter_test.rb
188
189
  - test/html/pipeline/toc_filter_test.rb
190
+ - test/html/pipeline_test.rb
189
191
  - test/test_helper.rb
190
192
  homepage: https://github.com/jch/html-pipeline
191
193
  licenses:
@@ -213,6 +215,7 @@ signing_key:
213
215
  specification_version: 3
214
216
  summary: Helpers for processing content through a chain of filters
215
217
  test_files:
218
+ - test/helpers/mocked_instrumentation_service.rb
216
219
  - test/html/pipeline/absolute_source_filter_test.rb
217
220
  - test/html/pipeline/autolink_filter_test.rb
218
221
  - test/html/pipeline/camo_filter_test.rb
@@ -223,4 +226,5 @@ test_files:
223
226
  - test/html/pipeline/plain_text_input_filter_test.rb
224
227
  - test/html/pipeline/sanitization_filter_test.rb
225
228
  - test/html/pipeline/toc_filter_test.rb
229
+ - test/html/pipeline_test.rb
226
230
  - test/test_helper.rb