html-pipeline 0.0.10 → 0.0.11

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