super 0.0.16 → 0.19.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/super/application.js +1401 -125
  3. data/app/assets/stylesheets/super/application.css +90702 -90026
  4. data/app/controllers/super/application_controller.rb +49 -6
  5. data/app/controllers/super/substructure_controller.rb +121 -37
  6. data/app/views/layouts/super/application.html.erb +1 -1
  7. data/app/views/super/application/_batch_button.html.erb +12 -0
  8. data/app/views/super/application/_batch_checkbox.csv.erb +1 -0
  9. data/app/views/super/application/_batch_checkbox.html.erb +5 -0
  10. data/app/views/super/application/_batch_form.html.erb +3 -0
  11. data/app/views/super/application/_collection_header.html.erb +7 -6
  12. data/app/views/super/application/_csv_button.html.erb +25 -0
  13. data/app/views/super/application/_display_actions.html.erb +2 -2
  14. data/app/views/super/application/_filter.html.erb +62 -2
  15. data/app/views/super/application/_layout.html.erb +13 -14
  16. data/app/views/super/application/_link.html.erb +8 -0
  17. data/app/views/super/application/_member_header.html.erb +7 -7
  18. data/app/views/super/application/_pagination.html.erb +1 -0
  19. data/app/views/super/application/_site_header.html.erb +4 -4
  20. data/app/views/super/application/_sort_expression.html.erb +2 -2
  21. data/app/views/super/application/_view_chain.html.erb +5 -0
  22. data/app/views/super/application/index.csv.erb +14 -0
  23. data/config/locales/en.yml +8 -0
  24. data/frontend/super-frontend/dist/application.css +90702 -90026
  25. data/frontend/super-frontend/dist/application.js +1401 -125
  26. data/frontend/super-frontend/dist/package.json +13 -0
  27. data/lib/generators/super/webpacker/USAGE +1 -7
  28. data/lib/generators/super/webpacker/templates/pack_super_application.js.tt +2 -0
  29. data/lib/generators/super/webpacker/webpacker_generator.rb +10 -6
  30. data/lib/super/cheat.rb +1 -0
  31. data/lib/super/display/guesser.rb +1 -1
  32. data/lib/super/display/schema_types.rb +6 -1
  33. data/lib/super/display.rb +2 -1
  34. data/lib/super/engine.rb +5 -0
  35. data/lib/super/error.rb +12 -0
  36. data/lib/super/filter/form_object.rb +74 -48
  37. data/lib/super/filter/guesser.rb +2 -0
  38. data/lib/super/filter/operator.rb +90 -64
  39. data/lib/super/filter/schema_types.rb +63 -80
  40. data/lib/super/filter.rb +1 -1
  41. data/lib/super/form/builder.rb +6 -3
  42. data/lib/super/form/field_transcript.rb +43 -0
  43. data/lib/super/form/guesser.rb +1 -1
  44. data/lib/super/form/schema_types.rb +11 -20
  45. data/lib/super/layout.rb +9 -33
  46. data/lib/super/link.rb +2 -7
  47. data/lib/super/link_builder.rb +0 -4
  48. data/lib/super/packaged_asset.rb +49 -0
  49. data/lib/super/pagination.rb +2 -1
  50. data/lib/super/reorderable_hash.rb +88 -0
  51. data/lib/super/reset.rb +20 -1
  52. data/lib/super/schema.rb +4 -0
  53. data/lib/super/version.rb +1 -1
  54. data/lib/super/view_chain.rb +25 -0
  55. data/lib/super.rb +4 -0
  56. metadata +46 -9
  57. data/app/views/super/application/_filter_type_select.html.erb +0 -21
  58. data/app/views/super/application/_filter_type_text.html.erb +0 -18
  59. data/app/views/super/application/_filter_type_timestamp.html.erb +0 -24
  60. data/app/views/super/application/_form_field_select.html.erb +0 -1
  61. data/lib/generators/super/webpacker/templates/pack_super_application.js.erb.tt +0 -2
@@ -2,112 +2,95 @@
2
2
 
3
3
  module Super
4
4
  class Filter
5
- # This schema type is used to configure the filtering form on your +#index+
6
- # action.
7
- #
8
- # The +operators:+ keyword argument can be left out in each case. There is
9
- # a default set of operators that are provided.
10
- #
11
5
  # Note: The constants under "Defined Under Namespace" are considered
12
6
  # private.
13
- #
14
- # class MemberDashboard
15
- # # ...
16
- #
17
- # def filter_schema
18
- # Super::Filter.new do |fields, type|
19
- # fields[:name] = type.text(operators: [
20
- # Super::Filter::Operator.eq,
21
- # Super::Filter::Operator.contain,
22
- # Super::Filter::Operator.ncontain,
23
- # Super::Filter::Operator.start,
24
- # Super::Filter::Operator.end,
25
- # ])
26
- # fields[:rank] = type.select(collection: Member.ranks.values)
27
- # fields[:position] = type.text(operators: [
28
- # Super::Filter::Operator.eq,
29
- # Super::Filter::Operator.neq,
30
- # Super::Filter::Operator.contain,
31
- # Super::Filter::Operator.ncontain,
32
- # ])
33
- # fields[:ship_id] = type.select(
34
- # collection: Ship.all.map { |s| ["#{s.name} (Ship ##{s.id})", s.id] },
35
- # )
36
- # fields[:created_at] = type.timestamp
37
- # fields[:updated_at] = type.timestamp
38
- # end
39
- # end
40
- #
41
- # # ...
42
- # end
43
7
  class SchemaTypes
44
- class Text
45
- def initialize(partial_path:, operators:)
46
- @partial_path = partial_path
47
- @operators = operators
48
- end
8
+ class OperatorList
9
+ include Enumerable
49
10
 
50
- attr_reader :operators
11
+ def initialize(*new_operators)
12
+ @operators = {}
13
+ @operator_transcript = {}
14
+ @fallback_transcript = nil
51
15
 
52
- def to_partial_path
53
- @partial_path
16
+ push(*new_operators)
54
17
  end
55
18
 
56
- def q
57
- [:q]
58
- end
59
- end
19
+ def push(*new_operators)
20
+ new_operators.flatten.map(&:dup).each do |new_operator|
21
+ new_identifier = new_operator.identifier.to_s
22
+
23
+ raise Error::AlreadyRegistered if @operators.key?(new_identifier)
60
24
 
61
- class Select
62
- def initialize(collection:, operators:)
63
- @collection = collection
64
- @operators = operators
25
+ @operators[new_identifier] = new_operator
26
+ end
27
+
28
+ nil
65
29
  end
66
30
 
67
- attr_reader :collection
68
- attr_reader :operators
31
+ alias add push
32
+
33
+ def each
34
+ return enum_for(:each) if !block_given?
69
35
 
70
- def to_partial_path
71
- "filter_type_select"
36
+ @operators.each do |identifier, operator|
37
+ yield(
38
+ OperatorWithFieldTranscript.new(
39
+ operator,
40
+ @operator_transcript[identifier] || @fallback_transcript
41
+ )
42
+ )
43
+ end
72
44
  end
73
45
 
74
- def q
75
- [:q]
46
+ def transcribe(operator_identifier = nil)
47
+ transcript = Form::FieldTranscript.new
48
+ yield transcript
49
+
50
+ if operator_identifier.nil?
51
+ @fallback_transcript = transcript
52
+ else
53
+ @operator_transcript[operator_identifier.to_s] = transcript
54
+ end
55
+
56
+ self
76
57
  end
77
58
  end
78
59
 
79
- class Timestamp
80
- def initialize(operators:)
81
- @operators = operators
60
+ class OperatorWithFieldTranscript
61
+ def initialize(operator, field_transcript)
62
+ @operator = operator
63
+ @field_transcript = field_transcript
82
64
  end
83
65
 
84
- attr_reader :operators
85
-
86
- def to_partial_path
87
- "filter_type_timestamp"
66
+ Super::Filter::Operator.instance_methods(false).each do |name|
67
+ delegate name, to: :@operator
88
68
  end
89
69
 
90
- def q
91
- [:q0, :q1]
92
- end
70
+ attr_reader :field_transcript
71
+ end
72
+
73
+ def use(*identifiers)
74
+ found_operators = identifiers.flatten.map { |id| Operator[id] }
75
+ OperatorList.new(*found_operators)
76
+ end
77
+
78
+ def select(collection)
79
+ use("eq", "null", "nnull")
80
+ .transcribe { |f| f.super.select(collection) }
93
81
  end
94
82
 
95
- def select(collection:, operators: Filter::Operator.select_defaults)
96
- Select.new(
97
- collection: collection,
98
- operators: operators
99
- )
83
+ def text
84
+ use("contain", "ncontain", "blank", "nblank")
100
85
  end
101
86
 
102
- def text(operators: Filter::Operator.text_defaults)
103
- Text.new(
104
- partial_path: "filter_type_text",
105
- operators: operators
106
- )
87
+ def timestamp
88
+ use("between", "null", "nnull")
89
+ .transcribe { |f| f.super.datetime_flatpickr }
107
90
  end
108
91
 
109
- def timestamp(operators: Filter::Operator.range_defaults)
110
- Timestamp.new(operators: operators)
92
+ def boolean
93
+ use("true", "false", "null", "nnull")
111
94
  end
112
95
  end
113
96
  end
data/lib/super/filter.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Super
4
4
  class Filter
5
5
  def initialize
6
- @schema_type = Filter::SchemaTypes.new
6
+ @schema_type = SchemaTypes.new
7
7
  @fields = Schema::Fields.new
8
8
 
9
9
  yield(@fields, @schema_type)
@@ -71,7 +71,8 @@ module Super
71
71
  )
72
72
  options[:class] = join_classes(defaults[:class], options[:class])
73
73
  options[:data] = defaults[:data].deep_merge(options[:data] || {})
74
- options[:value] = @builder.object.public_send(attribute).presence&.iso8601
74
+ options[:value] = @builder.object.public_send(attribute).presence
75
+ options[:value] = options[:value].iso8601 if options[:value].respond_to?(:iso8601)
75
76
 
76
77
  @builder.text_field(attribute, options)
77
78
  end
@@ -91,7 +92,8 @@ module Super
91
92
  )
92
93
  options[:class] = join_classes(defaults[:class], options[:class])
93
94
  options[:data] = defaults[:data].deep_merge(options[:data] || {})
94
- options[:value] = @builder.object.public_send(attribute).presence&.iso8601
95
+ options[:value] = @builder.object.public_send(attribute).presence
96
+ options[:value] = options[:value].iso8601 if options[:value].respond_to?(:iso8601)
95
97
 
96
98
  @builder.text_field(attribute, options)
97
99
  end
@@ -112,7 +114,8 @@ module Super
112
114
  )
113
115
  options[:class] = join_classes(defaults[:class], options[:class])
114
116
  options[:data] = defaults[:data].deep_merge(options[:data] || {})
115
- options[:value] = @builder.object.public_send(attribute).presence&.strftime("%H:%M:%S")
117
+ options[:value] = @builder.object.public_send(attribute).presence
118
+ options[:value] = options[:value].strftime("%H:%M:%S") if options[:value].respond_to?(:strftime)
116
119
 
117
120
  @builder.text_field(attribute, options)
118
121
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Form
5
+ # Holds a recording of a form field definition
6
+ class FieldTranscript
7
+ def initialize
8
+ @super = false
9
+ end
10
+
11
+ attr_reader :method_name
12
+ attr_reader :args
13
+ attr_reader :kwargs
14
+
15
+ def super
16
+ @super = true
17
+ self
18
+ end
19
+
20
+ def super?
21
+ @super
22
+ end
23
+
24
+ def method_missing(new_method_name, *args, **kwargs)
25
+ if @method_name.present?
26
+ method_chain =
27
+ if super?
28
+ "super.#{@method_name}"
29
+ else
30
+ @method_name.to_s
31
+ end
32
+
33
+ raise Error::AlreadyTranscribed, "This instance already holds a transcription for: #{method_chain}"
34
+ end
35
+
36
+ @method_name = new_method_name
37
+ @args = args
38
+ @kwargs = kwargs
39
+ @method_name
40
+ end
41
+ end
42
+ end
43
+ end
@@ -30,7 +30,7 @@ module Super
30
30
  when :date
31
31
  @type.date_flatpickr
32
32
  else
33
- @type.string
33
+ @type.text_field
34
34
  end
35
35
  end
36
36
  end
@@ -97,7 +97,7 @@ module Super
97
97
  @fields = fields
98
98
  end
99
99
 
100
- def generic(partial_path, **extras)
100
+ def partial(partial_path, **extras)
101
101
  Generic.new(partial_path: partial_path, extras: extras, nested: {})
102
102
  end
103
103
 
@@ -105,17 +105,14 @@ module Super
105
105
  Direct.new(super_builder: super_builder, method_name: method_name, args: args, kwargs: kwargs)
106
106
  end
107
107
 
108
- def select(**extras)
109
- Generic.new(partial_path: "form_field_select", extras: extras, nested: {})
108
+ def select(*args, **kwargs)
109
+ Direct.new(super_builder: true, method_name: :select!, args: args, kwargs: kwargs)
110
110
  end
111
111
 
112
112
  def text_field(*args, **kwargs)
113
113
  Direct.new(super_builder: true, method_name: :text_field!, args: args, kwargs: kwargs)
114
114
  end
115
115
 
116
- alias string text_field
117
- alias text text_field
118
-
119
116
  def rich_text_area(*args, **kwargs)
120
117
  Direct.new(super_builder: true, method_name: :rich_text_area!, args: args, kwargs: kwargs)
121
118
  end
@@ -124,20 +121,14 @@ module Super
124
121
  Direct.new(super_builder: true, method_name: :check_box!, args: args, kwargs: kwargs)
125
122
  end
126
123
 
127
- alias checkbox check_box
128
-
129
124
  def date_flatpickr(*args, **kwargs)
130
125
  Direct.new(super_builder: true, method_name: :date_flatpickr!, args: args, kwargs: kwargs)
131
126
  end
132
127
 
133
- alias flatpickr_date date_flatpickr
134
-
135
128
  def datetime_flatpickr(*args, **kwargs)
136
129
  Direct.new(super_builder: true, method_name: :datetime_flatpickr!, args: args, kwargs: kwargs)
137
130
  end
138
131
 
139
- alias flatpickr_datetime datetime_flatpickr
140
-
141
132
  def hidden_field(*args, **kwargs)
142
133
  Direct.new(super_builder: false, method_name: :hidden_field, args: args, kwargs: kwargs)
143
134
  end
@@ -150,29 +141,29 @@ module Super
150
141
  Direct.new(super_builder: true, method_name: :time_flatpickr!, args: args, kwargs: kwargs)
151
142
  end
152
143
 
153
- alias flatpickr_time time_flatpickr
154
-
155
144
  def has_many(reader, **extras)
156
- nested = @fields.nested do
157
- yield
145
+ subfields = Schema::Fields.new
146
+ @fields.nested do
147
+ yield subfields
158
148
  end
159
149
 
160
150
  Generic.new(
161
151
  partial_path: "form_has_many",
162
152
  extras: extras.merge(reader: reader),
163
- nested: nested
153
+ nested: subfields.to_h
164
154
  )
165
155
  end
166
156
 
167
157
  def has_one(reader, **extras)
168
- nested = @fields.nested do
169
- yield
158
+ subfields = Schema::Fields.new
159
+ @fields.nested do
160
+ yield subfields
170
161
  end
171
162
 
172
163
  Generic.new(
173
164
  partial_path: "form_has_one",
174
165
  extras: extras.merge(reader: reader),
175
- nested: nested
166
+ nested: subfields.to_h
176
167
  )
177
168
  end
178
169
 
data/lib/super/layout.rb CHANGED
@@ -6,44 +6,20 @@ module Super
6
6
  class Layout
7
7
  include Super::Partial::Resolving
8
8
 
9
- def initialize(headers: nil, asides: nil, mains: nil, footers: nil)
10
- @headers = Array(headers).compact
11
- @asides = Array(asides).compact
12
- @mains = Array(mains).compact
13
- @footers = Array(footers).compact
9
+ def initialize(header: nil, aside: nil, main: nil, footer: nil)
10
+ @header = header
11
+ @aside = aside
12
+ @main = main
13
+ @footer = footer
14
14
  end
15
15
 
16
- attr_reader :headers
17
- attr_reader :asides
18
- attr_reader :mains
19
- attr_reader :footers
16
+ attr_reader :header
17
+ attr_reader :aside
18
+ attr_reader :main
19
+ attr_reader :footer
20
20
 
21
21
  def to_partial_path
22
22
  "layout"
23
23
  end
24
-
25
- def resolve(template)
26
- @resolved_headers = resolve_for_rendering(template, headers, nil)
27
- @resolved_asides = resolve_for_rendering(template, asides, nil)
28
- @resolved_mains = resolve_for_rendering(template, mains, nil)
29
- @resolved_footers = resolve_for_rendering(template, footers, nil)
30
- self
31
- end
32
-
33
- def resolved_headers
34
- @resolved_headers || []
35
- end
36
-
37
- def resolved_asides
38
- @resolved_asides || []
39
- end
40
-
41
- def resolved_mains
42
- @resolved_mains || []
43
- end
44
-
45
- def resolved_footers
46
- @resolved_footers || []
47
- end
48
24
  end
49
25
  end
data/lib/super/link.rb CHANGED
@@ -107,13 +107,8 @@ module Super
107
107
  @href = Super::Compatability.polymorphic_path_container.polymorphic_path(@href)
108
108
  end
109
109
 
110
- def to_s(default_options: nil)
111
- default_options ||= {}
112
- ActionController::Base.helpers.link_to(
113
- text,
114
- href,
115
- default_options.deep_merge(options)
116
- )
110
+ def to_partial_path
111
+ "link"
117
112
  end
118
113
 
119
114
  def ==(other)
@@ -19,10 +19,6 @@ module Super
19
19
 
20
20
  attr_reader :requirements
21
21
 
22
- def to_s(default_options: nil, **kwargs)
23
- resolve(**kwargs).to_s(default_options: default_options)
24
- end
25
-
26
22
  def resolve(**kwargs)
27
23
  Link.new(
28
24
  into_value(@text, kwargs),
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class PackagedAsset
5
+ VERSION_BEGINNING = /\A\d+\.\d+.\d+/.freeze
6
+
7
+ class << self
8
+ attr_accessor :warning_message
9
+ end
10
+
11
+ def self.comparable_super_version
12
+ ::Super::VERSION[VERSION_BEGINNING]
13
+ end
14
+
15
+ def self.version_matches_gem?(package_json_path)
16
+ return true if ENV.key?("SUPER_IGNORE_PACKAGE_JSON_VERSION")
17
+
18
+ asset = new(package_json_path)
19
+
20
+ return true if !asset.comparable_version
21
+
22
+ asset.comparable_version == comparable_super_version
23
+ end
24
+
25
+ def initialize(package_json_path)
26
+ @package_json_path = package_json_path
27
+ end
28
+
29
+ def full_version
30
+ if instance_variable_defined?(:@full_version)
31
+ return @full_version
32
+ end
33
+
34
+ @full_version = JSON.parse(@package_json_path.read).dig("dependencies", "@superadministration/super")
35
+ rescue
36
+ @full_version = nil
37
+ end
38
+
39
+ def comparable_version
40
+ if instance_variable_defined?(:@asset_version)
41
+ return @asset_version
42
+ end
43
+
44
+ @asset_version = full_version[VERSION_BEGINNING]
45
+ rescue
46
+ @asset_version = nil
47
+ end
48
+ end
49
+ end
@@ -76,9 +76,10 @@ module Super
76
76
  module ControllerMethods
77
77
  def index
78
78
  super
79
+ return if !@records
79
80
  @pagination = initialize_pagination
80
81
  @records = paginate_records
81
- @view.mains.first.parts.push(:@pagination)
82
+ @view.main.insert(:pagination, @pagination, before: :main)
82
83
  end
83
84
  end
84
85
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class ReorderableHash
5
+ include TSort
6
+ include Enumerable
7
+
8
+ UNDEFINED = BasicObject.new
9
+
10
+ def initialize(data = {})
11
+ @data = data
12
+ @ordering = {}
13
+ keys = @data.keys
14
+ dependencies = []
15
+ keys.each do |key|
16
+ @ordering[key] = dependencies.dup
17
+ dependencies.push(key)
18
+ end
19
+ end
20
+
21
+ def insert(key, value, before: UNDEFINED, after: UNDEFINED)
22
+ if @ordering.key?(key) || @data.key?(key)
23
+ raise Super::Error::ReorderableHash::DuplicateKey, "Duplicate key: #{key}"
24
+ end
25
+ @ordering[key] = []
26
+ @data[key] = value
27
+
28
+ order(key, before: before, after: after)
29
+
30
+ nil
31
+ end
32
+
33
+ def order(key, before: UNDEFINED, after: UNDEFINED)
34
+ if before != UNDEFINED
35
+ if !@ordering.key?(before)
36
+ raise KeyError, "Before key not found. Have: #{@data.keys} Requested: #{before}"
37
+ end
38
+ @ordering[before].push(key)
39
+ end
40
+
41
+ if after != UNDEFINED
42
+ if !@ordering.key?(after)
43
+ raise KeyError, "After key not found. Have: #{@data.keys} Requested: #{after}"
44
+ end
45
+ @ordering[key].push(after)
46
+ end
47
+ end
48
+
49
+ def tsort_each_node(&block)
50
+ @ordering.each_key(&block)
51
+ end
52
+
53
+ def tsort_each_child(node, &block)
54
+ dependencies = @ordering.fetch(node) { [] }
55
+ dependencies.each(&block)
56
+ end
57
+
58
+ def []=(key, where, value)
59
+ insert(key, value, **where)
60
+ end
61
+
62
+ def keys
63
+ tsort
64
+ end
65
+
66
+ def values
67
+ keys.each_with_object([]) do |key, array|
68
+ array.push(@data[key])
69
+ end
70
+ end
71
+
72
+ def to_h
73
+ keys.each_with_object({}) do |key, hash|
74
+ hash[key] = @data[key]
75
+ end
76
+ end
77
+
78
+ def each
79
+ if !block_given?
80
+ return enum_for(:each)
81
+ end
82
+
83
+ tsort_each do |key|
84
+ yield key, @data[key]
85
+ end
86
+ end
87
+ end
88
+ end
data/lib/super/reset.rb CHANGED
@@ -4,6 +4,20 @@ module Super
4
4
  module Reset
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ KEEP = {
8
+ # Defined by Rails
9
+ _layout: true,
10
+ _generate_paths_by_default: true,
11
+
12
+ # Defined in Super::SubstructureController
13
+ navigation: true,
14
+ page_title: true,
15
+
16
+ # Defined in Super::ApplicationController
17
+ current_action: true,
18
+ with_current_action: true,
19
+ }
20
+
7
21
  included do
8
22
  undef_method :index
9
23
  undef_method :show
@@ -14,7 +28,12 @@ module Super
14
28
  undef_method :destroy
15
29
 
16
30
  Super::SubstructureController.private_instance_methods(false).each do |imethod|
17
- next if imethod == :navigation
31
+ next if KEEP.key?(imethod)
32
+ undef_method imethod
33
+ end
34
+
35
+ Super::ApplicationController.private_instance_methods(false).each do |imethod|
36
+ next if KEEP.key?(imethod)
18
37
  undef_method imethod
19
38
  end
20
39
  end
data/lib/super/schema.rb CHANGED
@@ -42,6 +42,10 @@ module Super
42
42
  enum_for(:each)
43
43
  end
44
44
 
45
+ def delete(key)
46
+ @backing.delete(key)
47
+ end
48
+
45
49
  def replace(other)
46
50
  @backing = other
47
51
  end
data/lib/super/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Super
4
- VERSION = "0.0.16"
4
+ VERSION = "0.19.0"
5
5
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class ViewChain
5
+ def initialize(chain)
6
+ @data = ReorderableHash.new(chain)
7
+ end
8
+
9
+ def chain
10
+ @chain ||= @data.values
11
+ end
12
+
13
+ def insert(*args, **kwargs)
14
+ if instance_variable_defined?(:@chain)
15
+ raise Error::ViewChain::ChainAlreadyStarted
16
+ end
17
+
18
+ @data.insert(*args, **kwargs)
19
+ end
20
+
21
+ def to_partial_path
22
+ "view_chain"
23
+ end
24
+ end
25
+ end