blueprinter 0.23.0 → 0.24.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: 2a1440e4adce199d743371035d3061ae69aea0ab8030bcbdabe59b23cd995c34
4
- data.tar.gz: b1a58870b18665b6bf1a7fe07ac3993cea0d25450c73a00f241f981ab4b9ad95
3
+ metadata.gz: 2d5e6d18d1ccf85eebe25b2aef41b629fbdad10a2972684e458bfbf268f266f0
4
+ data.tar.gz: a60400a4b58cb8d26db31838b8da490096b747d17b3912e119db413796d9f5ea
5
5
  SHA512:
6
- metadata.gz: b20e40f673a754d4d20ccacb2acc8caceeb79d0cced6f69bf4003fa6df6bde5c883baf40954d9fcc9dcde5394f489f54f8a9e1f3f4c3db8eb8494ea88d860e50
7
- data.tar.gz: 6192b46a62e77bb267c1b03f15686412efebbddf30dc10931941f2966ddc0bad4f97ec8823d3f4c939d9902c3cac89a3a5ebd209c61798314e2f94c94a537249
6
+ metadata.gz: 7c58a220d1187a9fa39514158b7e585576010b030da4430a41263ea4dc47f43d1a115e4b475230dfc4a995e1607f870b280d26182d012109013b3303fd75d7cd
7
+ data.tar.gz: a9a8380551402f4aace847aa1333269e4e2d6052dcf220ea94dbe8f2976a7abb6172558926417438085ca56f57ca744d6a94f1694380ab44c98df37aba9751c3
@@ -1,4 +1,19 @@
1
- ## 0.23.0 - 2019/1/31
1
+ ## 0.24.0 - 2020/6/22
2
+ * 🚀 [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).
3
+
4
+ ## 0.23.4 - 2020/4/28
5
+ * 🚀 [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).
6
+
7
+ ## 0.23.3 - 2020/4/7
8
+ * 🐛 [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).
9
+
10
+ ## 0.23.2 - 2020/3/16
11
+ * 🐛 [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).
12
+
13
+ ## 0.23.1 - 2020/3/13
14
+ * 🐛 [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).
15
+
16
+ ## 0.23.0 - 2020/1/31
2
17
  * 🚀 [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:
3
18
  ```
4
19
  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
 
@@ -427,8 +427,30 @@ module Blueprinter
427
427
  # @return [View] a Blueprinter::View object
428
428
  def self.view(view_name)
429
429
  @current_view = view_collection[view_name]
430
+ view_collection[:default].track_definition_order(view_name)
430
431
  yield
431
432
  @current_view = view_collection[:default]
432
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
433
455
  end
434
456
  end
@@ -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.0'.freeze
2
+ VERSION = '0.24.0'.freeze
3
3
  end
@@ -1,7 +1,8 @@
1
1
  module Blueprinter
2
2
  # @api private
3
+ DefinitionPlaceholder = Struct.new :name, :view?
3
4
  class View
4
- attr_reader :excluded_field_names, :fields, :included_view_names, :name, :transformers
5
+ attr_reader :excluded_field_names, :fields, :included_view_names, :name, :transformers, :definition_order
5
6
 
6
7
  def initialize(name, fields: {}, included_view_names: [], excluded_view_names: [],transformers: [])
7
8
  @name = name
@@ -9,6 +10,14 @@ module Blueprinter
9
10
  @included_view_names = included_view_names
10
11
  @excluded_field_names = excluded_view_names
11
12
  @transformers = transformers
13
+ @definition_order = []
14
+ @sort_by_definition = Blueprinter.configuration.sort_fields_by.eql?(:definition)
15
+ end
16
+
17
+ def track_definition_order(method, is_view = true)
18
+ if @sort_by_definition
19
+ @definition_order << DefinitionPlaceholder.new(method, is_view)
20
+ end
12
21
  end
13
22
 
14
23
  def inherit(view)
@@ -30,11 +39,13 @@ module Blueprinter
30
39
  end
31
40
 
32
41
  def include_view(view_name)
42
+ track_definition_order(view_name)
33
43
  included_view_names << view_name
34
44
  end
35
45
 
36
46
  def include_views(view_names)
37
47
  view_names.each do |view_name|
48
+ track_definition_order(view_name)
38
49
  included_view_names << view_name
39
50
  end
40
51
  end
@@ -54,6 +65,7 @@ module Blueprinter
54
65
  end
55
66
 
56
67
  def <<(field)
68
+ track_definition_order(field.name,false)
57
69
  fields[field.name] = field
58
70
  end
59
71
  end
@@ -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 = sortable_fields(view_name).values
27
- sorted_fields = sort_by_definition ? fields : fields.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,28 +43,46 @@ 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
- def merge_fields(source_fields, included_fields)
62
- if sort_by_definition
63
- included_fields.merge(source_fields)
65
+ # select and order members of fields according to traversal of the definition_orders
66
+ def sort_by_def(view_name, fields)
67
+ ordered_fields = {}
68
+ views[:default].definition_order.each { |definition| add_to_ordered_fields(ordered_fields, definition, fields, view_name) }
69
+ ordered_fields.values
70
+ end
71
+
72
+ # view_name_filter allows to follow definition order all the way down starting from the view_name given to sort_by_def()
73
+ # but include no others at the top-level
74
+ def add_to_ordered_fields(ordered_fields, definition, fields, view_name_filter = nil)
75
+ if definition.view?
76
+ if view_name_filter.nil? || view_name_filter == definition.name
77
+ views[definition.name].definition_order.each { |_definition| add_to_ordered_fields(ordered_fields, _definition, fields) }
78
+ end
64
79
  else
65
- source_fields.merge(included_fields)
80
+ ordered_fields[definition.name] = fields[definition.name]
66
81
  end
67
82
  end
83
+
84
+ def merge_fields(source_fields, included_fields)
85
+ source_fields.merge included_fields
86
+ end
68
87
  end
69
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.0
4
+ version: 0.24.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-01-31 00:00:00.000000000 Z
12
+ date: 2020-06-25 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