blueprinter 0.23.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
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