image_processing 1.2.0 → 1.12.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of image_processing might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39c52030a178edeef33439eb70807d86935b1e05bbf250d0f30aa9a4947f6dea
4
- data.tar.gz: 60c936577febb87380de300024a8f4517ae9dafed394d74fe7b0f78ab04efd7f
3
+ metadata.gz: ec4b4776480756b2721185419de81f228e5ca927b4bd3077fb4c0a5dcafef15f
4
+ data.tar.gz: d40b8822b6a7b2b5e1bad182099f7e3b23b25d0cdd6b61b1afa3154b665e76a6
5
5
  SHA512:
6
- metadata.gz: 9bc68c91084d44b3052a47ac332d21840965537163b541ef09cd662d729c26e152b3e588f97fd954a13aaae0a5a645be86389a79308de4eee154feb7fed95baa
7
- data.tar.gz: 4c026c8eb9cc4dfa537ef3f0f86b460a8dc0a13134fe441604483b6a4b1afd1048911b499673807fac82f7a15c37773e27fad1dd2d049f8e8adedd5204166923
6
+ metadata.gz: 77cff245646f56f409d4c1d006d26cee819d11cc9c263b88d86bafb6e480ac691240bfa17542bf9c578891056355d53f63fefddfa1f3eb801e3ddeea20666ae3
7
+ data.tar.gz: bf3f39c4204d7dcbb6382596a4a8850f8c7d22fee94e8ed77a1782a58bd1f370448268bb4e74028e429ee2e7c6156613b1022f5465faf6d30ab01833751c4df9
data/CHANGELOG.md CHANGED
@@ -1,112 +1,204 @@
1
+ ## 1.12.1 (2020-11-06)
2
+
3
+ * Fix format fallback for files ending with a dot on Ruby 2.7+ (@coding-chimp)
4
+
5
+ ## 1.12.0 (2020-09-20)
6
+
7
+ * Add instrumentation support via `#instrumenter` (@janko)
8
+
9
+ ## 1.11.0 (2020-05-17)
10
+
11
+ * [minimagick] Handle destination format having no file extension (@janko)
12
+
13
+ * [minimagick] Disable sharpening on `#resize_*` operators by default (@flori)
14
+
15
+ * [minimagick] Add `#crop` which accepts `left, top, width, height` arguments (@janko)
16
+
17
+ ## 1.10.3 (2020-01-12)
18
+
19
+ * [vips] Fix auto-rotation not working in certain cases on libvips 8.9.0 (@janko)
20
+
21
+ ## 1.10.2 (2020-01-11)
22
+
23
+ * Fix Ruby 2.7 warnings for separation of positional and keyword arguments (@kamipo, @janko)
24
+
25
+ ## 1.10.1 (2020-01-07)
26
+
27
+ * [vips] Fix compatibility with ruby-vips 2.0.17+ (@janko)
28
+
29
+ ## 1.10.0 (2019-12-18)
30
+
31
+ * [minimagick] Add `:loader` option for explicitly setting input file type (@janko)
32
+
33
+ ## 1.9.3 (2019-08-11)
34
+
35
+ * [vips] Use integer precision when sharpening for better quality (@metaskills)
36
+
37
+ ## 1.9.2 (2019-07-22)
38
+
39
+ * Bump `mini_magick` dependency to `>= 4.9.5` (@chioreandan)
40
+
41
+ ## 1.9.1 (2019-07-20)
42
+
43
+ * Bring back support for MRI 2.3 (@janko)
44
+
45
+ ## 1.9.0 (2019-04-09)
46
+
47
+ * Drop support for MRI 2.2 and 2.3 (@janko)
48
+
49
+ * [vips] Allow forcing a specific loader or saver (@janko)
50
+
51
+ ## 1.8.0 (2019-02-25)
52
+
53
+ * [vips] Perform resize-on-load when possible, significantly improving resizing speed (@janko)
54
+
55
+ ## 1.7.1 (2018-09-27)
56
+
57
+ * [vips] Make `#remove` that's used for removing image metadata chainable (@janko)
58
+
59
+ ## 1.7.0 (2018-09-20)
60
+
61
+ * [vips] `#rotate` now always calls `vips_similarity()` and forwards all options to it (@janko)
62
+
63
+ ## 1.6.0 (2018-07-13)
64
+
65
+ * [vips] In `#composite` accept `:offset` option for the position of the overlay image (@janko)
66
+
67
+ * [vips] In `#composite` accept `:gravity` option for the direction of the overlay image (@janko)
68
+
69
+ * [vips] In `#composite` accept blend mode as an optional `:mode` parameter which defaults to `:over` (@janko)
70
+
71
+ * [minimagick] In `#composite` rename `:compose` option to `:mode` (@janko)
72
+
73
+ * [minimagick] In `#composite` replace `:geometry` option with `:offset` which accepts an array (@janko)
74
+
75
+ ## 1.5.0 (2018-07-10)
76
+
77
+ * [minimagick, vips] Add `#composite` method (@janko)
78
+
79
+ * [core] Allow operations to accept blocks (janko-m)
80
+
81
+ ## 1.4.0 (2018-06-14)
82
+
83
+ * [minimagick] Accept RGB(A) arrays for color names for `:background` (@janko)
84
+
85
+ * [minimagick] Don't add empty `-background` option in `#rotate` when `:background` is not given (@janko)
86
+
87
+ * [vips] Modify `#rotate` to accept only `:background` and not other `vips_similarity()` options (@janko)
88
+
89
+ ## 1.3.0 (2018-06-13)
90
+
91
+ * [minimagick, vips] Add `#rotate` method (@janko)
92
+
93
+ * [vips] Use native `vips_image_hasalpha()` and `vips_addalpha()` functions in `#resize_and_pad` (@janko)
94
+
1
95
  ## 1.2.0 (2018-04-18)
2
96
 
3
- * [minimagick] Allow appending "+" operators in `#loader` and `#saver` using the value `false` (@janko-m)
97
+ * [minimagick] Allow appending "+" operators in `#loader` and `#saver` using the value `false` (@janko)
4
98
 
5
- * [core] Fix `#apply` not accepting a Hash as an argument (@janko-m)
99
+ * [core] Fix `#apply` not accepting a Hash as an argument (@janko)
6
100
 
7
- * [core] Allow sending any builder commands via `#apply`, not just operations (@janko-m)
101
+ * [core] Allow sending any builder commands via `#apply`, not just operations (@janko)
8
102
 
9
- * [minimagick] Add `#define` as a wrapper around `-define` (@janko-m)
103
+ * [minimagick] Add `#define` as a wrapper around `-define` (@janko)
10
104
 
11
105
  ## 1.1.0 (2018-04-05)
12
106
 
13
107
  * [minimagick] Disallow splitting multi-layer images into multiple single-layer
14
108
  images by default to avoid unexpected behaviour, but can be re-enabled with
15
- the `:allow_splitting` saver option (@janko-m)
109
+ the `:allow_splitting` saver option (@janko)
16
110
 
17
- * [core] Add `#apply` for applying a list of operations (@janko-m)
111
+ * [core] Add `#apply` for applying a list of operations (@janko)
18
112
 
19
113
  ## 1.0.0 (2018-04-04)
20
114
 
21
- * Depend on `mini_magick` and `ruby-vips` gems (@janko-m, @mokolabs)
115
+ * Depend on `mini_magick` and `ruby-vips` gems (@janko, @mokolabs)
22
116
 
23
- * [minimagick] Remove deprecated API in favor of the chainable API (@janko-m)
117
+ * [minimagick] Remove deprecated API in favor of the chainable API (@janko)
24
118
 
25
- * [core] Rename `Builder#default_options` to `Builder#options` (@janko-m)
119
+ * [core] Rename `Builder#default_options` to `Builder#options` (@janko)
26
120
 
27
- * [minimagick] Remove `:fail` loader option in favor of the existing `:regard_warnings` (@janko-m)
121
+ * [minimagick] Remove `:fail` loader option in favor of the existing `:regard_warnings` (@janko)
28
122
 
29
- * [vips, minimagick] Don't fail on warnings when loading the image (@janko-m)
123
+ * [vips, minimagick] Don't fail on warnings when loading the image (@janko)
30
124
 
31
- * [vips] Don't apply `Vips::Image#autorot` if `:autorotate` loader option was passed in (@janko-m)
125
+ * [vips] Don't apply `Vips::Image#autorot` if `:autorotate` loader option was passed in (@janko)
32
126
 
33
- * [minimagick] Allow using value `nil` to add ImageMagick options that don't have a value (@janko-m)
127
+ * [minimagick] Allow using value `nil` to add ImageMagick options that don't have a value (@janko)
34
128
 
35
- * [vips] Accept `:quality` saver option as an alias to `:Q` (@janko-m)
129
+ * [vips] Accept `:quality` saver option as an alias to `:Q` (@janko)
36
130
 
37
- * [minimagick] Automatically sharpen thumbnails after resizing (@janko-m, @mokolabs)
131
+ * [minimagick] Automatically sharpen thumbnails after resizing (@janko, @mokolabs)
38
132
 
39
- * [vips] Automatically sharpen thumbnails after resizing (@janko-m, @mokolabs)
133
+ * [vips] Automatically sharpen thumbnails after resizing (@janko, @mokolabs)
40
134
 
41
135
  ## 0.11.2 (2018-03-31)
42
136
 
43
- * [minimagick] Avoid `#resize_*` operations stripping data by switching back to `-resize` (@janko-m)
44
-
45
- * [core] Make sure an empty destination file doesn't remain on processing errors when `:destination` is used (@janko-m)
137
+ * [minimagick] Avoid `#resize_*` operations stripping data by switching back to `-resize` (@janko)
46
138
 
47
- * [vips] Fix `:alpha` not correctly adding alpha for certain types of images (@janko-m)
139
+ * [core] Make sure an empty destination file doesn't remain on processing errors when `:destination` is used (@janko)
48
140
 
49
- * [minimagick] Drop official support for GraphicsMagick (@janko-m)
141
+ * [vips] Fix `:alpha` not correctly adding alpha for certain types of images (@janko)
50
142
 
51
143
  ## 0.11.1 (2018-03-27)
52
144
 
53
- * [minimagick] Rename `#limit` to `#limits` to still allow adding `-limit` arguments directly (@janko-m)
145
+ * [minimagick] Rename `#limit` to `#limits` to still allow adding `-limit` arguments directly (@janko)
54
146
 
55
147
  ## 0.11.0 (2018-03-27)
56
148
 
57
- * [minimagick] Fix broken deprecated `#convert` (@janko-m)
149
+ * [minimagick] Fix broken deprecated `#convert` (@janko)
58
150
 
59
- * [minimagick] Add `#limit` for specifying resource limits using `-limit` (@janko-m)
151
+ * [minimagick] Add `#limit` for specifying resource limits using `-limit` (@janko)
60
152
 
61
- * [minimagick] Use `-thumbnail` instead of `-resize` in `#resize_*` methods (@janko-m)
153
+ * [minimagick] Use `-thumbnail` instead of `-resize` in `#resize_*` methods (@janko)
62
154
 
63
- * [minimagick] Add loader and saver options (@janko-m)
155
+ * [minimagick] Add loader and saver options (@janko)
64
156
 
65
157
  ## 0.10.3 (2018-03-24)
66
158
 
67
- * [minimagick] Fix bang methods in deprecated API calling nondestructive versions (@janko-m)
159
+ * [minimagick] Fix bang methods in deprecated API calling nondestructive versions (@janko)
68
160
 
69
161
  ## 0.10.2 (2018-03-22)
70
162
 
71
- * [minimagick] Add back default offset arguments to deprecated `#crop` (@janko-m)
163
+ * [minimagick] Add back default offset arguments to deprecated `#crop` (@janko)
72
164
 
73
165
  ## 0.10.1 (2018-03-22)
74
166
 
75
- * [minimagick] Don't print deprecation warning for old API twice when IO objects are used (@janko-m)
167
+ * [minimagick] Don't print deprecation warning for old API twice when IO objects are used (@janko)
76
168
 
77
169
  ## 0.10.0 (2018-03-21)
78
170
 
79
- * [minimagick] Rewrite MiniMagick module to use the chainable API (@janko-m)
171
+ * [minimagick] Rewrite MiniMagick module to use the chainable API (@janko)
80
172
 
81
- * [minimagick] Deprecate the old API (@janko-m)
173
+ * [minimagick] Deprecate the old API (@janko)
82
174
 
83
- * [minimagick] Raise an exception on processing warnings (@janko-m)
175
+ * [minimagick] Raise an exception on processing warnings (@janko)
84
176
 
85
- * [minimagick] Speed up `.valid_image?` by an order of magnitude (@janko-m)
177
+ * [minimagick] Speed up `.valid_image?` by an order of magnitude (@janko)
86
178
 
87
- * [minimagick] Don't accept arbitrary IO object anymore (@janko-m)
179
+ * [minimagick] Don't accept arbitrary IO object anymore (@janko)
88
180
 
89
- * [minimagick] Removed unnecessary `#crop` and `#resample` macros (@janko-m)
181
+ * [minimagick] Removed unnecessary `#crop` and `#resample` macros (@janko)
90
182
 
91
- * [vips] Ignore undefined loader/saver options (@janko-m)
183
+ * [vips] Ignore undefined loader/saver options (@janko)
92
184
 
93
- * [vips] Preserve transparent background in `#resize_to_pad` (@janko-m)
185
+ * [vips] Preserve transparent background in `#resize_to_pad` (@janko)
94
186
 
95
- * [vips] Remove the ability to specify colors using names (@janko-m)
187
+ * [vips] Remove the ability to specify colors using names (@janko)
96
188
 
97
- * [minimagick, vips] Autorotate images after loading them (@janko-m)
189
+ * [minimagick, vips] Autorotate images after loading them (@janko)
98
190
 
99
- * [core] Delete result `Tempfile` object in case of processing errors (@janko-m)
191
+ * [core] Delete result `Tempfile` object in case of processing errors (@janko)
100
192
 
101
- * [core] Allow returning `nil` in the `#custom` block (@janko-m)
193
+ * [core] Allow returning `nil` in the `#custom` block (@janko)
102
194
 
103
- * [core] Allow specifying a path string as source file (@janko-m)
195
+ * [core] Allow specifying a path string as source file (@janko)
104
196
 
105
- * [core] Allow saving to a specific location with the `:destination` call option (@janko-m)
197
+ * [core] Allow saving to a specific location with the `:destination` call option (@janko)
106
198
 
107
199
  ## 0.9.0 (2018-03-16)
108
200
 
109
- * Added libvips module (@GustavoCaso, @janko-m)
201
+ * Added libvips module (@GustavoCaso, @janko)
110
202
 
111
203
  * Drop official support for MRI 2.0 and 2.1
112
204
 
@@ -116,15 +208,15 @@
116
208
 
117
209
  ## 0.4.4 (2017-06-16)
118
210
 
119
- * Fix last changes being incompatible with older Ruby versions, again (@janko-m)
211
+ * Fix last changes being incompatible with older Ruby versions, again (@janko)
120
212
 
121
213
  ## 0.4.3 (2017-06-16)
122
214
 
123
- * Fix last changes being incompatible with older Ruby versions (@janko-m)
215
+ * Fix last changes being incompatible with older Ruby versions (@janko)
124
216
 
125
217
  ## 0.4.2 (2017-06-16)
126
218
 
127
- * Don't use path of input file as basename for output file (@janko-m)
219
+ * Don't use path of input file as basename for output file (@janko)
128
220
 
129
221
  ## 0.4.1 (2016-09-08)
130
222
 
data/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  Provides higher-level image processing helpers that are commonly needed
4
4
  when handling image uploads.
5
5
 
6
- This gem can process images with either [ImageMagick] or [libvips] libraries.
7
- ImageMagick is a good default choice, especially if you are migrating from
8
- another gem or library that uses ImageMagick. Libvips is a newer library that
9
- can process images [very rapidly][libvips performance] (up to 10x faster than
10
- ImageMagick).
6
+ This gem can process images with either [ImageMagick]/[GraphicsMagick] or
7
+ [libvips] libraries. ImageMagick is a good default choice, especially if you
8
+ are migrating from another gem or library that uses ImageMagick. Libvips is a
9
+ newer library that can process images [very rapidly][libvips performance]
10
+ (often multiple times faster than ImageMagick).
11
11
 
12
12
 
13
13
  ## Goal
@@ -42,9 +42,9 @@ how to resize and process images.
42
42
 
43
43
  ## Usage
44
44
 
45
- Processing is performed through [`ImageProcessing::Vips`] or
46
- [`ImageProcessing::MiniMagick`] modules. Both modules share the same chainable
47
- API for defining the processing pipeline:
45
+ Processing is performed through **[`ImageProcessing::Vips`]** or
46
+ **[`ImageProcessing::MiniMagick`]** modules. Both modules share the same
47
+ chainable API for defining the processing pipeline:
48
48
 
49
49
  ```rb
50
50
  require "image_processing/mini_magick"
@@ -117,7 +117,8 @@ pipeline.options
117
117
  ```
118
118
 
119
119
  The source object needs to responds to `#path`, or be a String, a Pathname, or
120
- a `Vips::Image`/`MiniMagick::Tool` object.
120
+ a `Vips::Image`/`MiniMagick::Tool` object. Note that the processed file is
121
+ always saved to a new location, in-place processing is not supported.
121
122
 
122
123
  ```rb
123
124
  ImageProcessing::Vips.source(File.open("source.jpg"))
@@ -144,8 +145,37 @@ You can continue reading the API documentation for specific modules:
144
145
  * **[`ImageProcessing::Vips`]**
145
146
  * **[`ImageProcessing::MiniMagick`]**
146
147
 
147
- See the **[wiki]** for additional "How To" guides for common scenarios.
148
+ See the **[wiki]** for additional "How To" guides for common scenarios. The wiki
149
+ is publicly editable, so you're encouraged to add your own guides.
148
150
 
151
+ ## Instrumentation
152
+
153
+ You can register an `#instrumenter` block for a given pipeline, which will wrap
154
+ the pipeline execution, allowing you to record performance metrics.
155
+
156
+ ```rb
157
+ pipeline = ImageProcessing::Vips.instrumenter do |**options, &processing|
158
+ options[:source] #=> #<File:...>
159
+ options[:loader] #=> { fail: true }
160
+ options[:saver] #=> { quality: 85 }
161
+ options[:format] #=> "png"
162
+ options[:operations] #=> [[:resize_to_limit, 500, 500], [:flip, [:horizontal]]]
163
+ options[:processor] #=> ImageProcessing::Vips::Processor
164
+
165
+ ActiveSupport::Notifications.instrument("process.image_processing", **options) do
166
+ processing.call # calls the pipeline
167
+ end
168
+ end
169
+
170
+ pipeline
171
+ .source(image)
172
+ .loader(fail: true)
173
+ .saver(quality: 85)
174
+ .convert("png")
175
+ .resize_to_limit(500, 500)
176
+ .flip(:horizontal)
177
+ .call # calls instrumenter
178
+ ```
149
179
 
150
180
  ## Contributing
151
181
 
@@ -179,11 +209,12 @@ The `ImageProcessing::MiniMagick` functionality was extracted from
179
209
 
180
210
  [MIT](LICENSE.txt)
181
211
 
182
- [libvips]: http://jcupitt.github.io/libvips/
212
+ [libvips]: http://libvips.github.io/libvips/
183
213
  [ImageMagick]: https://www.imagemagick.org
184
- [`ImageProcessing::Vips`]: /doc/vips.md#imageprocessingvips
185
- [`ImageProcessing::MiniMagick`]: /doc/minimagick.md#imageprocessingminimagick
214
+ [GraphicsMagick]: http://www.graphicsmagick.org
215
+ [`ImageProcessing::Vips`]: doc/vips.md#readme
216
+ [`ImageProcessing::MiniMagick`]: doc/minimagick.md#readme
186
217
  [refile-mini_magick]: https://github.com/refile/refile-mini_magick
187
- [wiki]: https://github.com/janko-m/image_processing/wiki
218
+ [wiki]: https://github.com/janko/image_processing/wiki
188
219
  [HTTP.rb]: https://github.com/httprb/http
189
- [libvips performance]: https://github.com/jcupitt/libvips/wiki/Speed-and-memory-use
220
+ [libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use
@@ -1,14 +1,14 @@
1
- require File.expand_path('../lib/image_processing/version', __FILE__)
1
+ require File.expand_path("../lib/image_processing/version", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "image_processing"
5
5
  spec.version = ImageProcessing::VERSION
6
6
 
7
- spec.required_ruby_version = ">= 2.0"
7
+ spec.required_ruby_version = ">= 2.3"
8
8
 
9
- spec.summary = "Set of higher-level helper methods for image processing."
10
- spec.description = "Set of higher-level helper methods for image processing."
11
- spec.homepage = "https://github.com/janko-m/image_processing"
9
+ spec.summary = "High-level wrapper for processing images for the web with ImageMagick or libvips."
10
+ spec.description = "High-level wrapper for processing images for the web with ImageMagick or libvips."
11
+ spec.homepage = "https://github.com/janko/image_processing"
12
12
  spec.authors = ["Janko Marohnić"]
13
13
  spec.email = ["janko.marohnic@gmail.com"]
14
14
  spec.license = "MIT"
@@ -16,8 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*.rb", "*.gemspec"]
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "mini_magick", "~> 4.0"
20
- spec.add_dependency "ruby-vips", ">= 2.0.10", "< 3"
19
+ spec.add_dependency "mini_magick", ">= 4.9.5", "< 5"
20
+ spec.add_dependency "ruby-vips", ">= 2.0.17", "< 3"
21
21
 
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "minitest", "~> 5.8"
@@ -8,8 +8,25 @@ module ImageProcessing
8
8
  @options = options
9
9
  end
10
10
 
11
- def call!(**options)
12
- Pipeline.new(self.options).call(**options)
11
+ # Calls the pipeline to perform the processing from built options.
12
+ def call!(**call_options)
13
+ instrument do
14
+ Pipeline.new(pipeline_options).call(**call_options)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def instrument
21
+ return yield unless options[:instrumenter]
22
+
23
+ result = nil
24
+ options[:instrumenter].call(**pipeline_options) { result = yield }
25
+ result
26
+ end
27
+
28
+ def pipeline_options
29
+ options.reject { |key, _| key == :instrumenter }
13
30
  end
14
31
  end
15
32
  end
@@ -1,77 +1,102 @@
1
1
  module ImageProcessing
2
+ # Implements a chainable interface for building processing options.
2
3
  module Chainable
4
+ # Specify the source image file.
3
5
  def source(file)
4
6
  branch source: file
5
7
  end
6
8
 
9
+ # Specify the output format.
7
10
  def convert(format)
8
11
  branch format: format
9
12
  end
10
13
 
14
+ # Specify processor options applied when loading the image.
11
15
  def loader(**options)
12
16
  branch loader: options
13
17
  end
14
18
 
19
+ # Specify processor options applied when saving the image.
15
20
  def saver(**options)
16
21
  branch saver: options
17
22
  end
18
23
 
19
- def custom(&block)
20
- operation :custom, block
24
+ # Register instrumentation block that will be called around the pipeline.
25
+ def instrumenter(&block)
26
+ branch instrumenter: block
21
27
  end
22
28
 
29
+ # Add multiple operations as a hash or an array.
30
+ #
31
+ # .apply(resize_to_limit: [400, 400], strip: true)
32
+ # # or
33
+ # .apply([[:resize_to_limit, [400, 400]], [:strip, true])
23
34
  def apply(operations)
24
35
  operations.inject(self) do |builder, (name, argument)|
25
36
  if argument == true || argument == nil
26
37
  builder.send(name)
27
38
  elsif argument.is_a?(Array)
28
39
  builder.send(name, *argument)
40
+ elsif argument.is_a?(Hash)
41
+ builder.send(name, **argument)
29
42
  else
30
43
  builder.send(name, argument)
31
44
  end
32
45
  end
33
46
  end
34
47
 
35
- def method_missing(name, *args)
36
- return super if name.to_s.end_with?("?")
37
- return send(name.to_s.chomp("!"), *args).call if name.to_s.end_with?("!")
38
-
39
- operation name, *args
40
- end
41
-
42
- def operation(name, *args)
43
- branch operations: [[name, args]]
48
+ # Add an operation defined by the processor.
49
+ def operation(name, *args, &block)
50
+ branch operations: [[name, args, *block]]
44
51
  end
45
52
 
53
+ # Call the defined processing and get the result. Allows specifying
54
+ # the source file and destination.
46
55
  def call(file = nil, destination: nil, **call_options)
47
- options = {}
48
- options = options.merge(source: file) if file
49
- options = options.merge(destination: destination) if destination
56
+ options = { source: file, destination: destination }.compact
50
57
 
51
- branch(options).call!(**call_options)
58
+ branch(**options).call!(**call_options)
52
59
  end
53
60
 
54
- def branch(loader: nil, saver: nil, operations: nil, **other_options)
55
- options = respond_to?(:options) ? self.options : DEFAULT_OPTIONS
61
+ # Creates a new builder object, merging current options with new options.
62
+ def branch(**new_options)
63
+ if self.is_a?(Builder)
64
+ options = self.options
65
+ else
66
+ options = DEFAULT_OPTIONS.merge(processor: self::Processor)
67
+ end
56
68
 
57
- options = options.merge(loader: options[:loader].merge(loader)) if loader
58
- options = options.merge(saver: options[:saver].merge(saver)) if saver
59
- options = options.merge(operations: options[:operations] + operations) if operations
60
- options = options.merge(processor_class: self::Processor) unless self.is_a?(Builder)
61
- options = options.merge(other_options)
69
+ options = options.merge(new_options) do |key, old_value, new_value|
70
+ case key
71
+ when :loader, :saver then old_value.merge(new_value)
72
+ when :operations then old_value + new_value
73
+ else new_value
74
+ end
75
+ end
76
+
77
+ Builder.new(options.freeze)
78
+ end
62
79
 
63
- options.freeze
80
+ private
81
+
82
+ # Assume that any unknown method names an operation supported by the
83
+ # processor. Add a bang ("!") if you want processing to be performed.
84
+ def method_missing(name, *args, &block)
85
+ return super if name.to_s.end_with?("?")
86
+ return send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
64
87
 
65
- Builder.new(options)
88
+ operation(name, *args, &block)
66
89
  end
90
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
67
91
 
92
+ # Empty options which the builder starts with.
68
93
  DEFAULT_OPTIONS = {
69
- source: nil,
70
- loader: {},
71
- saver: {},
72
- format: nil,
73
- operations: [],
74
- processor_class: nil,
94
+ source: nil,
95
+ loader: {},
96
+ saver: {},
97
+ format: nil,
98
+ operations: [],
99
+ processor: nil,
75
100
  }.freeze
76
101
  end
77
102
  end