nti_receipt_builder 0.1.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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +21 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +272 -0
  6. data/Rakefile +12 -0
  7. data/app/assets/javascripts/nti_receipt_builder/index.js +16 -0
  8. data/app/assets/javascripts/nti_receipt_builder/receipt_builder_controller.js +297 -0
  9. data/app/assets/javascripts/nti_receipt_builder/receipt_canvas_controller.js +279 -0
  10. data/app/assets/javascripts/nti_receipt_builder/receipt_draggable_controller.js +154 -0
  11. data/app/assets/javascripts/nti_receipt_builder/receipt_print_controller.js +24 -0
  12. data/app/assets/javascripts/nti_receipt_builder/receipt_properties_controller.js +297 -0
  13. data/app/assets/stylesheets/nti_receipt_builder.css +238 -0
  14. data/app/controllers/concerns/nti_receipt_builder/templates_controller.rb +170 -0
  15. data/app/helpers/nti_receipt_builder/render_helper.rb +21 -0
  16. data/app/models/nti_receipt_builder/template.rb +79 -0
  17. data/app/views/nti_receipt_builder/render/_order_lines_element.html.erb +36 -0
  18. data/app/views/nti_receipt_builder/render/_overflow_banner.html.erb +5 -0
  19. data/app/views/nti_receipt_builder/render/_paper.html.erb +12 -0
  20. data/app/views/nti_receipt_builder/render/_text_element.html.erb +1 -0
  21. data/app/views/nti_receipt_builder/render/_variable_element.html.erb +1 -0
  22. data/app/views/nti_receipt_builder/templates/_canvas.html.erb +33 -0
  23. data/app/views/nti_receipt_builder/templates/_elements_panel.html.erb +49 -0
  24. data/app/views/nti_receipt_builder/templates/_errors.html.erb +21 -0
  25. data/app/views/nti_receipt_builder/templates/_lock_version_field.html.erb +2 -0
  26. data/app/views/nti_receipt_builder/templates/_print_assets.html.erb +15 -0
  27. data/app/views/nti_receipt_builder/templates/_properties_panel.html.erb +8 -0
  28. data/app/views/nti_receipt_builder/templates/_settings_panel.html.erb +130 -0
  29. data/app/views/nti_receipt_builder/templates/create.turbo_stream.erb +3 -0
  30. data/app/views/nti_receipt_builder/templates/edit.html.erb +54 -0
  31. data/app/views/nti_receipt_builder/templates/new.html.erb +115 -0
  32. data/app/views/nti_receipt_builder/templates/preview.html.erb +24 -0
  33. data/app/views/nti_receipt_builder/templates/print.html.erb +31 -0
  34. data/app/views/nti_receipt_builder/templates/render_preview.turbo_stream.erb +26 -0
  35. data/app/views/nti_receipt_builder/templates/update.turbo_stream.erb +7 -0
  36. data/config/importmap.rb +4 -0
  37. data/lib/generators/nti_receipt_builder/install_generator.rb +49 -0
  38. data/lib/generators/nti_receipt_builder/templates/create_nti_receipt_templates.rb +28 -0
  39. data/lib/generators/nti_receipt_builder/templates/initializer.rb +16 -0
  40. data/lib/generators/nti_receipt_builder/templates/turbo_stream_tags.rb +36 -0
  41. data/lib/nti_receipt_builder/configuration.rb +59 -0
  42. data/lib/nti_receipt_builder/elements.rb +46 -0
  43. data/lib/nti_receipt_builder/engine.rb +32 -0
  44. data/lib/nti_receipt_builder/errors.rb +13 -0
  45. data/lib/nti_receipt_builder/layout_validator.rb +285 -0
  46. data/lib/nti_receipt_builder/presenters/collection.rb +126 -0
  47. data/lib/nti_receipt_builder/presenters/element.rb +68 -0
  48. data/lib/nti_receipt_builder/render_result.rb +18 -0
  49. data/lib/nti_receipt_builder/renderer.rb +78 -0
  50. data/lib/nti_receipt_builder/set_default.rb +24 -0
  51. data/lib/nti_receipt_builder/template_form.rb +60 -0
  52. data/lib/nti_receipt_builder/type_inference.rb +26 -0
  53. data/lib/nti_receipt_builder/variable_definition.rb +74 -0
  54. data/lib/nti_receipt_builder/variable_resolver.rb +55 -0
  55. data/lib/nti_receipt_builder/variables.rb +159 -0
  56. data/lib/nti_receipt_builder/version.rb +5 -0
  57. data/lib/nti_receipt_builder.rb +50 -0
  58. metadata +175 -0
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NtiReceiptBuilder
4
+ # One receipt placeholder: where its value comes from, how it is labelled, how it is
5
+ # formatted, and what stands in for it in the designer preview.
6
+ #
7
+ # Frozen on construction — these are read on every render and must never be mutated.
8
+ class VariableDefinition
9
+ DEFAULT_SAMPLE_ROW_COUNT = 3
10
+ # Matches the builder's default order_lines element width, so freshly dropped tables fill it.
11
+ DEFAULT_COLLECTION_WIDTH_MM = 60.0
12
+ DEFAULT_COLUMN_ALIGN = 'left'
13
+
14
+ attr_reader :key, :method_name, :label, :type, :columns
15
+
16
+ def initialize(key:, method_name:, label:, type: nil, sample: nil, columns: nil)
17
+ @key = -key.to_s
18
+ @method_name = -method_name.to_s
19
+ @label = -label.to_s
20
+ @type = type
21
+ @sample = sample
22
+ @columns = columns
23
+ freeze
24
+ end
25
+
26
+ # A variable that declares `columns:` IS the collection — there is no separate marker.
27
+ def collection? = !@columns.nil?
28
+
29
+ def column_keys = collection? ? @columns.keys : []
30
+
31
+ def column_label(column_key)
32
+ @columns&.dig(column_key, :label) || column_key.to_s.titleize
33
+ end
34
+
35
+ def column_type(column_key)
36
+ @columns&.dig(column_key, :type)
37
+ end
38
+
39
+ # The column set the builder uses when a designer drops a fresh table onto the canvas.
40
+ # Without this the builder would have to hardcode column keys, and any host whose columns
41
+ # differ would get a layout its own validator rejects.
42
+ def default_columns_config
43
+ return [] unless collection?
44
+
45
+ even_width_mm = (DEFAULT_COLLECTION_WIDTH_MM / column_keys.size).round(2)
46
+
47
+ column_keys.map do |column_key|
48
+ {
49
+ 'key' => column_key,
50
+ 'label' => column_label(column_key),
51
+ 'width_mm' => @columns.dig(column_key, :width_mm) || even_width_mm,
52
+ 'align' => @columns.dig(column_key, :align) || DEFAULT_COLUMN_ALIGN
53
+ }
54
+ end
55
+ end
56
+
57
+ # The declared sample, or a derived stand-in. Only ever called on the preview path, so
58
+ # nothing is memoised — a frozen object cannot memoise, and previews are not hot.
59
+ def sample
60
+ declared = @sample.respond_to?(:call) ? @sample.call : @sample
61
+ return declared unless declared.nil?
62
+
63
+ collection? ? derived_collection_sample : label
64
+ end
65
+
66
+ private
67
+
68
+ def derived_collection_sample
69
+ Array.new(DEFAULT_SAMPLE_ROW_COUNT) do |index|
70
+ column_keys.index_with { |column_key| "#{column_label(column_key)} #{index + 1}" }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module NtiReceiptBuilder
6
+ # Resolves every scalar variable to a formatted (not yet escaped) string. Missing keys
7
+ # resolve to nil so presenters can apply their own fallback.
8
+ #
9
+ # A declared type wins; otherwise the value's class decides. Collection variables are
10
+ # skipped — the collection presenter formats its own cells.
11
+ class VariableResolver
12
+ include ActionView::Helpers::NumberHelper
13
+
14
+ def initialize(data, definitions:)
15
+ @data = data || {}
16
+ @definitions = definitions
17
+ end
18
+
19
+ def call
20
+ definitions.each_with_object({}) do |(key, definition), resolved|
21
+ next if definition.collection?
22
+
23
+ resolved[key] = format_value(definition, data[key])
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :data, :definitions
30
+
31
+ def format_value(definition, value)
32
+ return nil if value.nil?
33
+
34
+ case definition.type || TypeInference.call(value)
35
+ when :currency then format_currency(value)
36
+ when :datetime then format_datetime(value)
37
+ else value.to_s
38
+ end
39
+ end
40
+
41
+ def format_currency(value)
42
+ number_to_currency(value, unit: NtiReceiptBuilder.config.currency_unit)
43
+ rescue StandardError
44
+ nil
45
+ end
46
+
47
+ def format_datetime(value)
48
+ return value.to_s unless value.respond_to?(:strftime)
49
+
50
+ value.strftime(NtiReceiptBuilder.config.datetime_format)
51
+ rescue StandardError
52
+ nil
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NtiReceiptBuilder
4
+ # Base class for a host application's receipt variable vocabulary.
5
+ #
6
+ # class OrderReceiptVariables < NtiReceiptBuilder::Variables
7
+ # MAPPINGS = {
8
+ # 'ORDER_REFERENCE' => 'order_reference',
9
+ # 'STORE_NAME' => 'store_name'
10
+ # }.freeze
11
+ #
12
+ # def order_reference = receipt_object.reference
13
+ # def store_name = receipt_object.address.name
14
+ # end
15
+ #
16
+ # MAPPINGS supplies the placeholder keys and the method producing each value. Everything
17
+ # else — label, formatting type, preview sample — is derived, and overridden per key with
18
+ # `variable`. The key that declares `columns:` is the collection.
19
+ #
20
+ # The schema is built once on first read and frozen, so render-path reads take no lock.
21
+ # It is memoised on the subclass itself, so a host code reload discards it along with the
22
+ # class it describes — there is no separate cache to invalidate and nothing that outlives
23
+ # what it points at.
24
+ class Variables
25
+ Schema = Struct.new(:definitions, :labels, :scalar_keys, :collection_key, keyword_init: true)
26
+ private_constant :Schema
27
+
28
+ class << self
29
+ # Override any derived aspect of a key already present in MAPPINGS.
30
+ #
31
+ # variable 'ORDER_DATETIME', label: 'Order Date/Time', sample: -> { Time.current }
32
+ # variable 'ORDER_LINES', columns: { 'description' => { label: 'Item' } }
33
+ #
34
+ # Column options: label:, type:, width_mm:, align: — all optional.
35
+ def variable(key, label: nil, type: nil, sample: nil, columns: nil)
36
+ overrides[key.to_s] = { label: label, type: type, sample: sample, columns: columns }
37
+ @schema = nil
38
+ self
39
+ end
40
+
41
+ def definitions = schema.definitions
42
+ def labels = schema.labels
43
+ def scalar_keys = schema.scalar_keys
44
+ def collection_key = schema.collection_key
45
+ def keys = definitions.keys
46
+ def collection_definition = collection_key && definitions[collection_key]
47
+
48
+ def sample_data
49
+ definitions.transform_values(&:sample)
50
+ end
51
+
52
+ def overrides
53
+ @overrides ||= {}
54
+ end
55
+
56
+ private
57
+
58
+ def schema
59
+ @schema ||= build_schema
60
+ end
61
+
62
+ def mappings
63
+ unless const_defined?(:MAPPINGS, false)
64
+ raise InvalidVariablesError, "#{inspect} must define a MAPPINGS constant"
65
+ end
66
+
67
+ const_get(:MAPPINGS, false)
68
+ end
69
+
70
+ def build_schema
71
+ raw = mappings
72
+ raise InvalidVariablesError, "#{inspect}: MAPPINGS must be a Hash" unless raw.is_a?(Hash)
73
+
74
+ validate_override_keys!(raw)
75
+ validate_mapped_methods!(raw)
76
+
77
+ definitions = build_definitions(raw)
78
+ validate_single_collection!(definitions)
79
+
80
+ Schema.new(
81
+ definitions: definitions,
82
+ labels: definitions.transform_values(&:label).freeze,
83
+ scalar_keys: definitions.reject { |_, definition| definition.collection? }.keys.freeze,
84
+ collection_key: definitions.each_value.find(&:collection?)&.key
85
+ ).freeze
86
+ end
87
+
88
+ def build_definitions(raw)
89
+ raw.each_with_object({}) do |(key, method_name), acc|
90
+ string_key = key.to_s
91
+ override = overrides.fetch(string_key, {})
92
+
93
+ acc[string_key] = VariableDefinition.new(
94
+ key: string_key,
95
+ method_name: method_name,
96
+ label: override[:label] || string_key.titleize,
97
+ type: override[:type],
98
+ sample: override[:sample],
99
+ columns: normalize_columns(override[:columns])
100
+ )
101
+ end.freeze
102
+ end
103
+
104
+ def normalize_columns(columns)
105
+ return nil if columns.nil?
106
+
107
+ columns.each_with_object({}) do |(column_key, options), acc|
108
+ acc[column_key.to_s] = {
109
+ label: options[:label],
110
+ type: options[:type],
111
+ width_mm: options[:width_mm],
112
+ align: options[:align]
113
+ }.compact.freeze
114
+ end.freeze
115
+ end
116
+
117
+ def validate_override_keys!(raw)
118
+ unknown = overrides.keys - raw.keys.map(&:to_s)
119
+ return if unknown.empty?
120
+
121
+ raise InvalidVariablesError,
122
+ "#{inspect}: `variable` called for keys not in MAPPINGS: #{unknown.join(', ')}"
123
+ end
124
+
125
+ def validate_mapped_methods!(raw)
126
+ missing = raw.values.map(&:to_s).reject do |method_name|
127
+ method_defined?(method_name) || private_method_defined?(method_name)
128
+ end
129
+ return if missing.empty?
130
+
131
+ raise InvalidVariablesError,
132
+ "#{inspect}: MAPPINGS references undefined methods: #{missing.join(', ')}"
133
+ end
134
+
135
+ def validate_single_collection!(definitions)
136
+ collections = definitions.each_value.select(&:collection?).map(&:key)
137
+ return if collections.size <= 1
138
+
139
+ raise InvalidVariablesError,
140
+ "#{inspect}: only one variable may declare `columns:` (got #{collections.join(', ')})"
141
+ end
142
+ end
143
+
144
+ attr_reader :receipt_object
145
+
146
+ def initialize(receipt_object)
147
+ @receipt_object = receipt_object
148
+ end
149
+
150
+ # Raw values, unformatted — VariableResolver applies formatting. An error raised by a
151
+ # mapping method propagates deliberately: a receipt printing silently without its total
152
+ # is worse than a visible failure.
153
+ def resolve
154
+ self.class.definitions.each_with_object({}) do |(key, definition), acc|
155
+ acc[key] = send(definition.method_name)
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NtiReceiptBuilder
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/string/inflections'
5
+ require 'active_support/core_ext/object/blank'
6
+ require 'active_support/core_ext/enumerable'
7
+
8
+ require_relative 'nti_receipt_builder/version'
9
+ require_relative 'nti_receipt_builder/errors'
10
+ require_relative 'nti_receipt_builder/configuration'
11
+ require_relative 'nti_receipt_builder/type_inference'
12
+ require_relative 'nti_receipt_builder/variable_definition'
13
+ require_relative 'nti_receipt_builder/variables'
14
+ require_relative 'nti_receipt_builder/elements'
15
+ require_relative 'nti_receipt_builder/layout_validator'
16
+ require_relative 'nti_receipt_builder/variable_resolver'
17
+ require_relative 'nti_receipt_builder/presenters/element'
18
+ require_relative 'nti_receipt_builder/presenters/collection'
19
+ require_relative 'nti_receipt_builder/render_result'
20
+ require_relative 'nti_receipt_builder/renderer'
21
+ require_relative 'nti_receipt_builder/set_default'
22
+ require_relative 'nti_receipt_builder/template_form'
23
+ require_relative 'nti_receipt_builder/engine' if defined?(Rails::Engine)
24
+
25
+ # A receipt template builder and renderer.
26
+ #
27
+ # NtiReceiptBuilder.configure { |config| config.variables_class = OrderReceiptVariables }
28
+ #
29
+ # The configured Variables subclass supplies the placeholder vocabulary, so the gem itself
30
+ # carries no domain terms. See NtiReceiptBuilder::Variables.
31
+ module NtiReceiptBuilder
32
+ class << self
33
+ def configure
34
+ yield(config) if block_given?
35
+ config
36
+ end
37
+
38
+ def config
39
+ @config ||= Configuration.new
40
+ end
41
+
42
+ # Resets configuration to defaults. Intended for test suites.
43
+ def reset_config!
44
+ @config = Configuration.new
45
+ end
46
+
47
+ def variables_class = config.variables_class
48
+ def template_class = config.template_class
49
+ end
50
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nti_receipt_builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Den Meralpis
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: actionview
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: activemodel
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: activerecord
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '7.1'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '7.1'
54
+ - !ruby/object:Gem::Dependency
55
+ name: activesupport
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '7.1'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '7.1'
68
+ - !ruby/object:Gem::Dependency
69
+ name: railties
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '7.1'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '7.1'
82
+ description: NtiReceiptBuilder ships a complete receipt designer — model, layout validation,
83
+ millimetre-accurate renderer, Stimulus builder UI and print views — as a Rails engine.
84
+ Host applications declare a Variables subclass that maps receipt placeholders to
85
+ methods on their own receipt object, so the gem carries no domain vocabulary of
86
+ its own.
87
+ email:
88
+ - denmark@nueca.com.ph
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - CHANGELOG.md
94
+ - CODE_OF_CONDUCT.md
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - app/assets/javascripts/nti_receipt_builder/index.js
99
+ - app/assets/javascripts/nti_receipt_builder/receipt_builder_controller.js
100
+ - app/assets/javascripts/nti_receipt_builder/receipt_canvas_controller.js
101
+ - app/assets/javascripts/nti_receipt_builder/receipt_draggable_controller.js
102
+ - app/assets/javascripts/nti_receipt_builder/receipt_print_controller.js
103
+ - app/assets/javascripts/nti_receipt_builder/receipt_properties_controller.js
104
+ - app/assets/stylesheets/nti_receipt_builder.css
105
+ - app/controllers/concerns/nti_receipt_builder/templates_controller.rb
106
+ - app/helpers/nti_receipt_builder/render_helper.rb
107
+ - app/models/nti_receipt_builder/template.rb
108
+ - app/views/nti_receipt_builder/render/_order_lines_element.html.erb
109
+ - app/views/nti_receipt_builder/render/_overflow_banner.html.erb
110
+ - app/views/nti_receipt_builder/render/_paper.html.erb
111
+ - app/views/nti_receipt_builder/render/_text_element.html.erb
112
+ - app/views/nti_receipt_builder/render/_variable_element.html.erb
113
+ - app/views/nti_receipt_builder/templates/_canvas.html.erb
114
+ - app/views/nti_receipt_builder/templates/_elements_panel.html.erb
115
+ - app/views/nti_receipt_builder/templates/_errors.html.erb
116
+ - app/views/nti_receipt_builder/templates/_lock_version_field.html.erb
117
+ - app/views/nti_receipt_builder/templates/_print_assets.html.erb
118
+ - app/views/nti_receipt_builder/templates/_properties_panel.html.erb
119
+ - app/views/nti_receipt_builder/templates/_settings_panel.html.erb
120
+ - app/views/nti_receipt_builder/templates/create.turbo_stream.erb
121
+ - app/views/nti_receipt_builder/templates/edit.html.erb
122
+ - app/views/nti_receipt_builder/templates/new.html.erb
123
+ - app/views/nti_receipt_builder/templates/preview.html.erb
124
+ - app/views/nti_receipt_builder/templates/print.html.erb
125
+ - app/views/nti_receipt_builder/templates/render_preview.turbo_stream.erb
126
+ - app/views/nti_receipt_builder/templates/update.turbo_stream.erb
127
+ - config/importmap.rb
128
+ - lib/generators/nti_receipt_builder/install_generator.rb
129
+ - lib/generators/nti_receipt_builder/templates/create_nti_receipt_templates.rb
130
+ - lib/generators/nti_receipt_builder/templates/initializer.rb
131
+ - lib/generators/nti_receipt_builder/templates/turbo_stream_tags.rb
132
+ - lib/nti_receipt_builder.rb
133
+ - lib/nti_receipt_builder/configuration.rb
134
+ - lib/nti_receipt_builder/elements.rb
135
+ - lib/nti_receipt_builder/engine.rb
136
+ - lib/nti_receipt_builder/errors.rb
137
+ - lib/nti_receipt_builder/layout_validator.rb
138
+ - lib/nti_receipt_builder/presenters/collection.rb
139
+ - lib/nti_receipt_builder/presenters/element.rb
140
+ - lib/nti_receipt_builder/render_result.rb
141
+ - lib/nti_receipt_builder/renderer.rb
142
+ - lib/nti_receipt_builder/set_default.rb
143
+ - lib/nti_receipt_builder/template_form.rb
144
+ - lib/nti_receipt_builder/type_inference.rb
145
+ - lib/nti_receipt_builder/variable_definition.rb
146
+ - lib/nti_receipt_builder/variable_resolver.rb
147
+ - lib/nti_receipt_builder/variables.rb
148
+ - lib/nti_receipt_builder/version.rb
149
+ homepage: https://github.com/nueca-tech/nti_receipt_builder
150
+ licenses:
151
+ - MIT
152
+ metadata:
153
+ allowed_push_host: https://rubygems.org
154
+ homepage_uri: https://github.com/nueca-tech/nti_receipt_builder
155
+ source_code_uri: https://github.com/nueca-tech/nti_receipt_builder
156
+ changelog_uri: https://github.com/nueca-tech/nti_receipt_builder/blob/main/CHANGELOG.md
157
+ rubygems_mfa_required: 'true'
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: 3.4.0
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ requirements: []
172
+ rubygems_version: 4.0.16
173
+ specification_version: 4
174
+ summary: A drag-and-drop receipt template builder and renderer for Rails.
175
+ test_files: []