blueprinter 0.23.1 → 0.25.0

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
  SHA256:
3
- metadata.gz: 1a290d1ace21669c5f28a726e25b634570cf8da35654f51b0901a46fcd36de94
4
- data.tar.gz: c065c391df542d56b63e1668096d0e83f14e67819e9e69360667290ec4d4b16a
3
+ metadata.gz: c47449bb382533a5c9dab64108c3eec2078f4f1ceba16a9cde3c46b23cb1dcc9
4
+ data.tar.gz: ea6d7fb604c37ad0bceb6db63a300da7c7946bb49ef0696ed416a674fe95f01a
5
5
  SHA512:
6
- metadata.gz: 91c21f6610e95ff9221a7a546d215f5fcef23de42e6429fe72af7ebee134bb2a5550b4a283cecf178d837f19ec12b8df782cc5bd42c5088ab8da4af09ff9d8a6
7
- data.tar.gz: d5832253816c04b5309c7e589730f5d28ca9ef2e0dffe7cd0879bf860a360ee95b6e953062571ca83656c273612a07bd53ef70986db431b3ecf69740b3ebba6f
6
+ metadata.gz: 48c8207d8f6a721feb45df8c15c128a73166478d708725a561861704eec7d041d92c08b8a5032bda2bba67cab138c0988976026732340086320b723e0ecab465
7
+ data.tar.gz: 1c818d65fb75800ff01ebdb15470626a2e83af578e16ef0537d67005dbb014366da34d504970fc7501e4d2fc9031601710ee4943f79fd4145ce965da06cd6e1d
@@ -1,7 +1,22 @@
1
- ## 0.23.1 - 2019/3/13
2
- * 🚀 [BUGFIX] Fixes #172 where views would unintentionally ignore `sort_fields_by: :definition` configuration. Resolved in [#197](https://github.com/procore/blueprinter/pull/197) by [@wlkrw](https://github.com/wlkrw).
1
+ ## 0.25.0 - 2020/7/06
2
+ * 🚀 [FEATURE] Enable default `Blueprinter::Transformer`s to be set in the global configuration. [#222](https://github.com/procore/blueprinter/pull/222). Thanks to [@supremebeing7](https://github.com/supremebeing7).
3
3
 
4
- ## 0.23.0 - 2019/1/31
4
+ ## 0.24.0 - 2020/6/22
5
+ * 🚀 [FEATURE] Add an `options` option to associations to facilitate passing options from one blueprint to another. [#220](https://github.com/procore/blueprinter/pull/220). Thanks to [@mcclayton](https://github.com/mcclayton).
6
+
7
+ ## 0.23.4 - 2020/4/28
8
+ * 🚀 [FEATURE] Public class method `has_view?` on Blueprinter::Base subclasses introduced in [#213](https://github.com/procore/blueprinter/pull/213). Thanks to [@spencerneste](https://github.com/spencerneste).
9
+
10
+ ## 0.23.3 - 2020/4/7
11
+ * 🐛 [BUGFIX] Fixes issue where `exclude` fields in deeply nested views were not respected. Resolved issue [207](https://github.com/procore/blueprinter/issues/207) in [#208](https://github.com/procore/blueprinter/pull/208) by [@tpltn](https://github.com/tpltn).
12
+
13
+ ## 0.23.2 - 2020/3/16
14
+ * 🐛 [BUGFIX] Fixes issue where fields "bled" into other views due to merge side-effects. Resolved issue [205](https://github.com/procore/blueprinter/issues/205) in [#204](https://github.com/procore/blueprinter/pull/204) by [@trevorrjohn](https://github.com/trevorrjohn).
15
+
16
+ ## 0.23.1 - 2020/3/13
17
+ * 🐛 [BUGFIX] Fixes #172 where views would unintentionally ignore `sort_fields_by: :definition` configuration. Resolved in [#197](https://github.com/procore/blueprinter/pull/197) by [@wlkrw](https://github.com/wlkrw).
18
+
19
+ ## 0.23.0 - 2020/1/31
5
20
  * 🚀 [FEATURE] Configurable default extractor introduced in [#198](https://github.com/procore/blueprinter/pull/198) by [@wlkrw](https://github.com/wlkrw). You can now set a default extractor like so:
6
21
  ```
7
22
  Blueprinter.configure do |config|
data/README.md CHANGED
@@ -355,6 +355,26 @@ Output:
355
355
  }
356
356
  ```
357
357
 
358
+ It is also possible to pass options from one Blueprint to another via an association.
359
+ For example:
360
+ ```ruby
361
+ class VehicleBlueprint < Blueprinter::Base
362
+ identifier :uuid
363
+ field :full_name do |vehicle, options|
364
+ "#{vehicle.model} #{options[:trim]}"
365
+ end
366
+ end
367
+
368
+ class DriverBlueprint < Blueprinter::Base
369
+ identifier :uuid
370
+
371
+ view :normal do
372
+ fields :first_name, :last_name
373
+ association :vehicles, blueprint: vehicle_blueprint, options: { trim: 'LX' }
374
+ end
375
+ end
376
+ ```
377
+
358
378
  ---
359
379
  </details>
360
380
 
@@ -739,6 +759,25 @@ class UserBlueprint < Blueprinter::Base
739
759
  end
740
760
  ```
741
761
 
762
+ #### Global Transforms
763
+
764
+ You can also specify global default transformers. Create one or more transformer classes extending from `Blueprinter::Transformer` and set the `default_transformers` configuration
765
+ ```ruby
766
+ class LowerCamelTransformer < Blueprinter::Transformer
767
+ def transform(hash, _object, _options)
768
+ hash.transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
769
+ end
770
+ end
771
+ ```
772
+
773
+ ```ruby
774
+ Blueprinter.configure do |config|
775
+ config.default_transformers = [LowerCamelTransformer]
776
+ end
777
+ ```
778
+
779
+ **Note: Any transforms specified on a per-blueprint or per-view level will override the `default_transformers` in the configuration.**
780
+
742
781
  ---
743
782
  </details>
744
783
 
@@ -431,5 +431,26 @@ module Blueprinter
431
431
  yield
432
432
  @current_view = view_collection[:default]
433
433
  end
434
+
435
+ # Check whether or not a Blueprint supports the supplied view.
436
+ # It accepts a view name.
437
+ #
438
+ # @param view_name [Symbol] the view name
439
+ #
440
+ # @example With the following Blueprint
441
+ #
442
+ # class ExampleBlueprint < Blueprinter::Base
443
+ # view :custom do
444
+ # end
445
+ # end
446
+ #
447
+ # ExampleBlueprint.has_view?(:custom) => true
448
+ # ExampleBlueprint.has_view?(:doesnt_exist) => false
449
+ #
450
+ # @return [Boolean] a boolean value indicating if the view is
451
+ # supported by this Blueprint.
452
+ def self.has_view?(view_name)
453
+ view_collection.has_view? view_name
454
+ end
434
455
  end
435
456
  end
@@ -1,6 +1,6 @@
1
1
  module Blueprinter
2
2
  class Configuration
3
- attr_accessor :association_default, :datetime_format, :field_default, :generator, :if, :method, :sort_fields_by, :unless, :extractor_default
3
+ attr_accessor :association_default, :datetime_format, :field_default, :generator, :if, :method, :sort_fields_by, :unless, :extractor_default, :default_transformers
4
4
 
5
5
  VALID_CALLABLES = %i(if unless).freeze
6
6
 
@@ -14,6 +14,7 @@ module Blueprinter
14
14
  @sort_fields_by = :name_asc
15
15
  @unless = nil
16
16
  @extractor_default = AutoExtractor
17
+ @default_transformers = []
17
18
  end
18
19
 
19
20
  def jsonify(blob)
@@ -9,6 +9,8 @@ module Blueprinter
9
9
 
10
10
  def extract(association_name, object, local_options, options={})
11
11
  options_without_default = options.reject { |k,_| k == :default || k == :default_if }
12
+ # Merge in assocation options hash
13
+ local_options = local_options.merge(options[:options]) if options[:options].is_a?(Hash)
12
14
  value = @extractor.extract(association_name, object, local_options, options_without_default)
13
15
  return default_value(options) if use_default_value?(value, options[:default_if])
14
16
  view = options[:view] || :default
@@ -1,3 +1,3 @@
1
1
  module Blueprinter
2
- VERSION = '0.23.1'.freeze
2
+ VERSION = '0.25.0'.freeze
3
3
  end
@@ -2,18 +2,22 @@ module Blueprinter
2
2
  # @api private
3
3
  DefinitionPlaceholder = Struct.new :name, :view?
4
4
  class View
5
- attr_reader :excluded_field_names, :fields, :included_view_names, :name, :transformers, :definition_order
5
+ attr_reader :excluded_field_names, :fields, :included_view_names, :name, :view_transformers, :definition_order
6
6
 
7
- def initialize(name, fields: {}, included_view_names: [], excluded_view_names: [],transformers: [])
7
+ def initialize(name, fields: {}, included_view_names: [], excluded_view_names: [], transformers: [])
8
8
  @name = name
9
9
  @fields = fields
10
10
  @included_view_names = included_view_names
11
11
  @excluded_field_names = excluded_view_names
12
- @transformers = transformers
12
+ @view_transformers = transformers
13
13
  @definition_order = []
14
14
  @sort_by_definition = Blueprinter.configuration.sort_fields_by.eql?(:definition)
15
15
  end
16
16
 
17
+ def transformers
18
+ view_transformers.empty? ? Blueprinter.configuration.default_transformers : view_transformers
19
+ end
20
+
17
21
  def track_definition_order(method, is_view = true)
18
22
  if @sort_by_definition
19
23
  @definition_order << DefinitionPlaceholder.new(method, is_view)
@@ -33,8 +37,8 @@ module Blueprinter
33
37
  exclude_field(field_name)
34
38
  end
35
39
 
36
- view.transformers.each do |transformer|
37
- self.add_transformer(transformer)
40
+ view.view_transformers.each do |transformer|
41
+ add_transformer(transformer)
38
42
  end
39
43
  end
40
44
 
@@ -61,7 +65,7 @@ module Blueprinter
61
65
  end
62
66
 
63
67
  def add_transformer(custom_transformer)
64
- transformers << custom_transformer
68
+ view_transformers << custom_transformer
65
69
  end
66
70
 
67
71
  def <<(field)
@@ -23,9 +23,10 @@ module Blueprinter
23
23
  def fields_for(view_name)
24
24
  return identifier_fields if view_name == :identifier
25
25
 
26
- fields_hash = sortable_fields(view_name)
27
- sorted_fields = sort_by_definition ? sort_by_def(view_name, fields_hash) : fields_hash.values.sort_by(&:name)
28
- identifier_fields + sorted_fields
26
+ fields, excluded_fields = sortable_fields(view_name)
27
+ sorted_fields = sort_by_definition ? sort_by_def(view_name, fields) : fields.values.sort_by(&:name)
28
+
29
+ (identifier_fields + sorted_fields).reject { |field| excluded_fields.include?(field.name) }
29
30
  end
30
31
 
31
32
  def transformers(view_name)
@@ -42,20 +43,23 @@ module Blueprinter
42
43
  views[:identifier].fields.values
43
44
  end
44
45
 
46
+ # @param [String] view_name
47
+ # @return [Array<(Hash, Hash<String, NilClass>)>] fields, excluded_fields
45
48
  def sortable_fields(view_name)
49
+ excluded_fields = {}
46
50
  fields = views[:default].fields
47
51
  fields = merge_fields(fields, views[view_name].fields)
48
52
  views[view_name].included_view_names.each do |included_view_name|
49
- if view_name != included_view_name
50
- fields = merge_fields(fields, sortable_fields(included_view_name))
51
- end
52
- end
53
+ next if view_name == included_view_name
53
54
 
54
- views[view_name].excluded_field_names.each do |name|
55
- fields.delete(name)
55
+ view_fields, view_excluded_fields = sortable_fields(included_view_name)
56
+ fields = merge_fields(fields, view_fields)
57
+ excluded_fields.merge!(view_excluded_fields)
56
58
  end
57
59
 
58
- fields
60
+ views[view_name].excluded_field_names.each { |name| excluded_fields[name] = nil }
61
+
62
+ [fields, excluded_fields]
59
63
  end
60
64
 
61
65
  # select and order members of fields according to traversal of the definition_orders
@@ -78,7 +82,7 @@ module Blueprinter
78
82
  end
79
83
 
80
84
  def merge_fields(source_fields, included_fields)
81
- source_fields.merge! included_fields
85
+ source_fields.merge included_fields
82
86
  end
83
87
  end
84
88
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blueprinter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.1
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hess
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-03-14 00:00:00.000000000 Z
12
+ date: 2020-07-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: factory_bot
@@ -123,6 +123,20 @@ dependencies:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
125
  version: '3.7'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rspec-rails
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "<"
131
+ - !ruby/object:Gem::Version
132
+ version: 4.0.0
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "<"
138
+ - !ruby/object:Gem::Version
139
+ version: 4.0.0
126
140
  - !ruby/object:Gem::Dependency
127
141
  name: sqlite3
128
142
  requirement: !ruby/object:Gem::Requirement