acts_as_calculator 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 (81) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +38 -0
  4. data/CODE_OF_CONDUCT.md +132 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +133 -0
  7. data/Rakefile +12 -0
  8. data/app/controllers/acts_as_calculator/application_controller.rb +76 -0
  9. data/app/controllers/acts_as_calculator/formula_versions_controller.rb +50 -0
  10. data/app/controllers/acts_as_calculator/formulas_controller.rb +58 -0
  11. data/app/controllers/acts_as_calculator/imports_controller.rb +33 -0
  12. data/app/controllers/acts_as_calculator/templates_controller.rb +66 -0
  13. data/app/models/acts_as_calculator/formula.rb +21 -0
  14. data/app/models/acts_as_calculator/formula_version.rb +88 -0
  15. data/app/models/acts_as_calculator/lookup_table.rb +25 -0
  16. data/app/models/acts_as_calculator/lookup_table_entry.rb +26 -0
  17. data/app/models/acts_as_calculator/record.rb +12 -0
  18. data/app/models/acts_as_calculator/run.rb +24 -0
  19. data/app/models/acts_as_calculator/template.rb +56 -0
  20. data/app/models/acts_as_calculator/variable.rb +20 -0
  21. data/config/routes.rb +36 -0
  22. data/lib/acts_as_calculator/aggregate_results.rb +57 -0
  23. data/lib/acts_as_calculator/aggregation.rb +9 -0
  24. data/lib/acts_as_calculator/apportion_amount.rb +62 -0
  25. data/lib/acts_as_calculator/apportionment.rb +57 -0
  26. data/lib/acts_as_calculator/build_calculator.rb +24 -0
  27. data/lib/acts_as_calculator/build_lookups.rb +37 -0
  28. data/lib/acts_as_calculator/calculable.rb +84 -0
  29. data/lib/acts_as_calculator/calculator_cache.rb +36 -0
  30. data/lib/acts_as_calculator/cast_date.rb +16 -0
  31. data/lib/acts_as_calculator/cast_decimal.rb +15 -0
  32. data/lib/acts_as_calculator/cast_json_safe.rb +37 -0
  33. data/lib/acts_as_calculator/cast_liquid_value.rb +58 -0
  34. data/lib/acts_as_calculator/cast_variable_attributes.rb +17 -0
  35. data/lib/acts_as_calculator/configuration.rb +31 -0
  36. data/lib/acts_as_calculator/distribute_remainder.rb +49 -0
  37. data/lib/acts_as_calculator/divide_proportionally.rb +27 -0
  38. data/lib/acts_as_calculator/engine.rb +19 -0
  39. data/lib/acts_as_calculator/errors.rb +23 -0
  40. data/lib/acts_as_calculator/evaluate_expression.rb +49 -0
  41. data/lib/acts_as_calculator/evaluate_formula.rb +53 -0
  42. data/lib/acts_as_calculator/find_lookup_table_references.rb +68 -0
  43. data/lib/acts_as_calculator/find_owned_record.rb +38 -0
  44. data/lib/acts_as_calculator/find_tier.rb +25 -0
  45. data/lib/acts_as_calculator/formula_version_drop.rb +55 -0
  46. data/lib/acts_as_calculator/function_registry.rb +83 -0
  47. data/lib/acts_as_calculator/import_definitions.rb +70 -0
  48. data/lib/acts_as_calculator/import_formula.rb +102 -0
  49. data/lib/acts_as_calculator/import_lookup_table.rb +94 -0
  50. data/lib/acts_as_calculator/import_outcome.rb +20 -0
  51. data/lib/acts_as_calculator/import_summary.rb +29 -0
  52. data/lib/acts_as_calculator/import_template.rb +57 -0
  53. data/lib/acts_as_calculator/liquid_filters.rb +70 -0
  54. data/lib/acts_as_calculator/persist_run.rb +31 -0
  55. data/lib/acts_as_calculator/promote_template.rb +21 -0
  56. data/lib/acts_as_calculator/publish_formula_version.rb +54 -0
  57. data/lib/acts_as_calculator/publish_template.rb +18 -0
  58. data/lib/acts_as_calculator/read_import_file.rb +23 -0
  59. data/lib/acts_as_calculator/render_liquid.rb +113 -0
  60. data/lib/acts_as_calculator/render_template.rb +43 -0
  61. data/lib/acts_as_calculator/resolve_formula_version.rb +57 -0
  62. data/lib/acts_as_calculator/resolve_import_owner.rb +38 -0
  63. data/lib/acts_as_calculator/resolve_template.rb +41 -0
  64. data/lib/acts_as_calculator/resolve_variables.rb +105 -0
  65. data/lib/acts_as_calculator/result.rb +32 -0
  66. data/lib/acts_as_calculator/result_drop.rb +46 -0
  67. data/lib/acts_as_calculator/serialize_formula.rb +18 -0
  68. data/lib/acts_as_calculator/serialize_formula_version.rb +26 -0
  69. data/lib/acts_as_calculator/serialize_import_summary.rb +21 -0
  70. data/lib/acts_as_calculator/serialize_template.rb +13 -0
  71. data/lib/acts_as_calculator/supersede_formula_versions.rb +83 -0
  72. data/lib/acts_as_calculator/tier.rb +31 -0
  73. data/lib/acts_as_calculator/variable_spec.rb +33 -0
  74. data/lib/acts_as_calculator/version.rb +5 -0
  75. data/lib/acts_as_calculator.rb +78 -0
  76. data/lib/generators/acts_as_calculator/import/import_generator.rb +26 -0
  77. data/lib/generators/acts_as_calculator/install/install_generator.rb +31 -0
  78. data/lib/generators/acts_as_calculator/install/templates/create_acts_as_calculator_tables.rb.tt +133 -0
  79. data/lib/tasks/acts_as_calculator.rake +21 -0
  80. data/sig/acts_as_calculator.rbs +4 -0
  81. metadata +251 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsCalculator
4
+ VariableSpec = Data.define(:name, :source_type, :source_config, :required) do
5
+ def self.build(source)
6
+ attributes = source.is_a?(Hash) ? source : read_from(source)
7
+ attributes = attributes.transform_keys(&:to_sym)
8
+ required = attributes[:required]
9
+ required = true if required.nil?
10
+
11
+ new(
12
+ name: attributes.fetch(:name).to_s,
13
+ source_type: (attributes[:source_type] || :context).to_sym,
14
+ source_config: (attributes[:source_config] || {}).transform_keys(&:to_sym),
15
+ required:
16
+ )
17
+ end
18
+
19
+ def self.read_from(source)
20
+ {
21
+ name: source.name,
22
+ source_type: source.source_type,
23
+ source_config: source.source_config,
24
+ required: source.respond_to?(:required) ? source.required : true
25
+ }
26
+ end
27
+ private_class_method :read_from
28
+
29
+ def default
30
+ source_config[:default]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsCalculator
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "dentaku"
5
+ require "liquid"
6
+
7
+ require_relative "acts_as_calculator/version"
8
+ require_relative "acts_as_calculator/errors"
9
+ require_relative "acts_as_calculator/configuration"
10
+ require_relative "acts_as_calculator/cast_decimal"
11
+ require_relative "acts_as_calculator/result"
12
+ require_relative "acts_as_calculator/tier"
13
+ require_relative "acts_as_calculator/variable_spec"
14
+ require_relative "acts_as_calculator/find_tier"
15
+ require_relative "acts_as_calculator/function_registry"
16
+ require_relative "acts_as_calculator/build_calculator"
17
+ require_relative "acts_as_calculator/evaluate_expression"
18
+ require_relative "acts_as_calculator/resolve_variables"
19
+ require_relative "acts_as_calculator/divide_proportionally"
20
+ require_relative "acts_as_calculator/distribute_remainder"
21
+ require_relative "acts_as_calculator/apportionment"
22
+ require_relative "acts_as_calculator/apportion_amount"
23
+ require_relative "acts_as_calculator/aggregation"
24
+ require_relative "acts_as_calculator/aggregate_results"
25
+ require_relative "acts_as_calculator/formula_version_drop"
26
+ require_relative "acts_as_calculator/result_drop"
27
+ require_relative "acts_as_calculator/cast_liquid_value"
28
+ require_relative "acts_as_calculator/liquid_filters"
29
+ require_relative "acts_as_calculator/render_liquid"
30
+
31
+ module ActsAsCalculator
32
+ # The scope every formula, lookup table and template falls into when a host doesn't
33
+ # namespace one. A non-null column beats a nullable one here because uniqueness is
34
+ # scoped on `[key, scope, owner_type, owner_id]` and NULLs never compare equal.
35
+ DEFAULT_SCOPE = "default"
36
+
37
+ # Defined here rather than in engine.rb because Engine.isolate_namespace only leaves
38
+ # this alone if the module already answers to it — otherwise it installs an
39
+ # `on_load(:active_record)` hook that redefines it to "acts_as_calculator_" long after
40
+ # the engine class body has run. The tables are named for what they hold.
41
+ def self.table_name_prefix
42
+ "calculator_"
43
+ end
44
+ end
45
+
46
+ require_relative "acts_as_calculator/cast_date"
47
+ require_relative "acts_as_calculator/cast_json_safe"
48
+ require_relative "acts_as_calculator/calculator_cache"
49
+ require_relative "acts_as_calculator/find_owned_record"
50
+ require_relative "acts_as_calculator/build_lookups"
51
+ require_relative "acts_as_calculator/resolve_formula_version"
52
+ require_relative "acts_as_calculator/persist_run"
53
+ require_relative "acts_as_calculator/evaluate_formula"
54
+ require_relative "acts_as_calculator/resolve_template"
55
+ require_relative "acts_as_calculator/promote_template"
56
+ require_relative "acts_as_calculator/render_template"
57
+ require_relative "acts_as_calculator/import_outcome"
58
+ require_relative "acts_as_calculator/import_summary"
59
+ require_relative "acts_as_calculator/read_import_file"
60
+ require_relative "acts_as_calculator/resolve_import_owner"
61
+ require_relative "acts_as_calculator/find_lookup_table_references"
62
+ require_relative "acts_as_calculator/supersede_formula_versions"
63
+ require_relative "acts_as_calculator/cast_variable_attributes"
64
+ require_relative "acts_as_calculator/publish_formula_version"
65
+ require_relative "acts_as_calculator/publish_template"
66
+ require_relative "acts_as_calculator/import_lookup_table"
67
+ require_relative "acts_as_calculator/import_formula"
68
+ require_relative "acts_as_calculator/import_template"
69
+ require_relative "acts_as_calculator/import_definitions"
70
+ require_relative "acts_as_calculator/serialize_formula_version"
71
+ require_relative "acts_as_calculator/serialize_formula"
72
+ require_relative "acts_as_calculator/serialize_template"
73
+ require_relative "acts_as_calculator/serialize_import_summary"
74
+
75
+ # Everything above is plain Ruby and stays loadable without Rails; the two below are the
76
+ # only files that touch a framework, so they load only when one is already present.
77
+ require_relative "acts_as_calculator/calculable" if defined?(::ActiveSupport)
78
+ require_relative "acts_as_calculator/engine" if defined?(::Rails::Engine)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module ActsAsCalculator
6
+ module Generators
7
+ # A thin wrapper: read the path, hand it to ImportDefinitions, print what happened.
8
+ # Deliberately no `source_root` and no templates — this generator writes rows, not files.
9
+ class ImportGenerator < ::Rails::Generators::Base
10
+ desc "Imports formulas, lookup tables and templates from a JSON file. Idempotent: " \
11
+ "re-importing an unchanged file changes nothing, and changed content becomes a " \
12
+ "new version rather than an edit to an existing one."
13
+
14
+ argument :path, type: :string, desc: "Path to the JSON import file"
15
+
16
+ def import
17
+ summary = ImportDefinitions.(path: File.expand_path(path, destination_root))
18
+ say summary.to_s
19
+
20
+ raise Thor::Error, "acts_as_calculator: #{summary.failures.size} import error(s)" unless summary.success?
21
+ rescue ActsAsCalculator::Error => e
22
+ raise Thor::Error, "acts_as_calculator: #{e.message}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module ActsAsCalculator
7
+ module Generators
8
+ class InstallGenerator < ::Rails::Generators::Base
9
+ include ::Rails::Generators::Migration
10
+
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ desc "Copies the acts_as_calculator migration for the six calculator_* tables."
14
+
15
+ def self.next_migration_number(dirname)
16
+ ::ActiveRecord::Generators::Base.next_migration_number(dirname)
17
+ end
18
+
19
+ def create_migration_file
20
+ migration_template "create_acts_as_calculator_tables.rb.tt",
21
+ "db/migrate/create_acts_as_calculator_tables.rb"
22
+ end
23
+
24
+ private
25
+
26
+ def migration_version
27
+ "[#{::ActiveRecord::Migration.current_version}]"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateActsAsCalculatorTables < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ create_table :calculator_formulas do |t|
6
+ t.string :key, null: false
7
+ t.string :scope, null: false, default: "default"
8
+ t.references :owner, polymorphic: true, null: true, index: false
9
+ t.timestamps
10
+ end
11
+ add_index :calculator_formulas, %i[key scope owner_type owner_id],
12
+ unique: true, name: "idx_calc_formulas_on_key_scope_owner"
13
+ add_index :calculator_formulas, %i[owner_type owner_id], name: "idx_calc_formulas_on_owner"
14
+
15
+ create_table :calculator_formula_versions do |t|
16
+ t.bigint :formula_id, null: false
17
+ t.integer :version_number, null: false
18
+ t.text :expression, null: false
19
+ t.date :effective_from, null: false
20
+ t.date :effective_to
21
+ t.string :status, null: false, default: "draft"
22
+ t.text :change_note
23
+ t.timestamps
24
+ end
25
+ add_index :calculator_formula_versions, %i[formula_id version_number],
26
+ unique: true, name: "idx_calc_versions_on_formula_and_number"
27
+ add_index :calculator_formula_versions, %i[formula_id status effective_from effective_to],
28
+ name: "idx_calc_versions_on_effective_range"
29
+ add_foreign_key :calculator_formula_versions, :calculator_formulas, column: :formula_id
30
+
31
+ create_table :calculator_variables do |t|
32
+ t.bigint :formula_version_id, null: false
33
+ t.string :name, null: false
34
+ t.string :source_type, null: false
35
+ t.column :source_config, json_type, null: false, default: {}
36
+ t.boolean :required, null: false, default: true
37
+ t.timestamps
38
+ end
39
+ add_index :calculator_variables, %i[formula_version_id name],
40
+ unique: true, name: "idx_calc_variables_on_version_and_name"
41
+ add_foreign_key :calculator_variables, :calculator_formula_versions, column: :formula_version_id
42
+
43
+ create_table :calculator_lookup_tables do |t|
44
+ t.string :key, null: false
45
+ t.string :scope, null: false, default: "default"
46
+ t.references :owner, polymorphic: true, null: true, index: false
47
+ t.timestamps
48
+ end
49
+ add_index :calculator_lookup_tables, %i[key scope owner_type owner_id],
50
+ unique: true, name: "idx_calc_lookup_tables_on_key_scope_owner"
51
+ add_index :calculator_lookup_tables, %i[owner_type owner_id], name: "idx_calc_lookup_tables_on_owner"
52
+
53
+ create_table :calculator_lookup_table_entries do |t|
54
+ t.bigint :lookup_table_id, null: false
55
+ t.integer :position, null: false, default: 0
56
+ t.decimal :from, precision: 20, scale: 6
57
+ t.decimal :to, precision: 20, scale: 6
58
+ t.decimal :value, precision: 20, scale: 6, null: false
59
+ t.timestamps
60
+ end
61
+ add_index :calculator_lookup_table_entries, %i[lookup_table_id position],
62
+ name: "idx_calc_lookup_entries_on_table_and_position"
63
+ add_foreign_key :calculator_lookup_table_entries, :calculator_lookup_tables, column: :lookup_table_id
64
+
65
+ create_table :calculator_templates do |t|
66
+ t.string :key, null: false
67
+ t.string :scope, null: false, default: "default"
68
+ t.references :owner, polymorphic: true, null: true, index: false
69
+ t.text :body, null: false
70
+ t.string :format, null: false, default: "html"
71
+ t.integer :version_number, null: false, default: 1
72
+ # Defaults to true so authoring a new version publishes it; rollback is pointing
73
+ # `current` back at an older row, which keeps the newer one in the history.
74
+ t.boolean :current, null: false, default: true
75
+ t.timestamps
76
+ end
77
+ add_index :calculator_templates, %i[key scope owner_type owner_id version_number],
78
+ unique: true, name: "idx_calc_templates_on_key_scope_owner_version"
79
+ add_index :calculator_templates, %i[owner_type owner_id], name: "idx_calc_templates_on_owner"
80
+
81
+ create_table :calculator_runs do |t|
82
+ t.references :calculable, polymorphic: true, null: false, index: false
83
+ t.bigint :formula_version_id, null: false
84
+ t.date :as_of_date, null: false
85
+ t.column :inputs, json_type, null: false, default: {}
86
+ t.column :breakdown, json_type, null: false, default: {}
87
+ t.decimal :result, precision: 30, scale: 10, null: false
88
+ t.timestamps
89
+ end
90
+ add_index :calculator_runs, %i[calculable_type calculable_id as_of_date],
91
+ name: "idx_calc_runs_on_calculable_and_date"
92
+ add_index :calculator_runs, :formula_version_id, name: "idx_calc_runs_on_formula_version"
93
+ add_foreign_key :calculator_runs, :calculator_formula_versions, column: :formula_version_id
94
+
95
+ add_global_uniqueness :calculator_formulas, %i[key scope], "idx_calc_formulas_global_key_scope"
96
+ add_global_uniqueness :calculator_lookup_tables, %i[key scope], "idx_calc_lookup_tables_global_key_scope"
97
+ add_global_uniqueness :calculator_templates, %i[key scope version_number],
98
+ "idx_calc_templates_global_key_scope_version"
99
+
100
+ add_single_current_template
101
+ end
102
+
103
+ private
104
+
105
+ # Exactly one version of a template may be current per [key, scope, owner]. Both halves
106
+ # are needed for the same reason as add_global_uniqueness: the composite index cannot
107
+ # constrain rows whose owner_id is NULL, so globally-owned templates get their own.
108
+ def add_single_current_template
109
+ return unless connection.supports_partial_index?
110
+
111
+ add_index :calculator_templates, %i[key scope owner_type owner_id],
112
+ unique: true, where: "current = TRUE", name: "idx_calc_templates_one_current"
113
+ add_index :calculator_templates, %i[key scope],
114
+ unique: true, where: "current = TRUE AND owner_id IS NULL",
115
+ name: "idx_calc_templates_one_current_global"
116
+ end
117
+
118
+ # A composite unique index over a nullable owner does not constrain globally-owned rows
119
+ # at all: NULLs never compare equal, so two `owner_id IS NULL` rows with the same key
120
+ # both slip past it. A partial index closes that on every adapter that has one; the
121
+ # model-level uniqueness validation is the only guard on the rest.
122
+ def add_global_uniqueness(table, columns, name)
123
+ return unless connection.supports_partial_index?
124
+
125
+ add_index table, columns, unique: true, where: "owner_id IS NULL", name: name
126
+ end
127
+
128
+ # jsonb is Postgres-only; every other adapter Rails ships gets its own json type, which
129
+ # for sqlite3 and older MySQL is text with JSON casting on top.
130
+ def json_type
131
+ connection.adapter_name.match?(/postgres/i) ? :jsonb : :json
132
+ end
133
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :acts_as_calculator do
4
+ desc "Imports formulas, lookup tables and templates from a JSON file " \
5
+ "(rake acts_as_calculator:import[config/calculator/payroll.json])"
6
+ task :import, [:path] => :environment do |_task, args|
7
+ path = args[:path]
8
+ abort("usage: rake acts_as_calculator:import[path/to/file.json]") if path.nil? || path.empty?
9
+
10
+ begin
11
+ summary = ActsAsCalculator::ImportDefinitions.(path:)
12
+ rescue ActsAsCalculator::Error => e
13
+ abort("acts_as_calculator: #{e.message}")
14
+ end
15
+
16
+ puts summary
17
+ # Non-zero on any failed entry so a deploy or CI step stops here rather than shipping a
18
+ # half-imported rule set.
19
+ abort("acts_as_calculator: #{summary.failures.size} import error(s)") unless summary.success?
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module ActsAsCalculator
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,251 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_calculator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - lautarograc
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-08-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bigdecimal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dentaku
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: liquid
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: actionpack
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '7.1'
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: '9'
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '7.1'
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '9'
75
+ - !ruby/object:Gem::Dependency
76
+ name: activerecord
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '7.1'
82
+ - - "<"
83
+ - !ruby/object:Gem::Version
84
+ version: '9'
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '7.1'
92
+ - - "<"
93
+ - !ruby/object:Gem::Version
94
+ version: '9'
95
+ - !ruby/object:Gem::Dependency
96
+ name: activesupport
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '7.1'
102
+ - - "<"
103
+ - !ruby/object:Gem::Version
104
+ version: '9'
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '7.1'
112
+ - - "<"
113
+ - !ruby/object:Gem::Version
114
+ version: '9'
115
+ - !ruby/object:Gem::Dependency
116
+ name: railties
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '7.1'
122
+ - - "<"
123
+ - !ruby/object:Gem::Version
124
+ version: '9'
125
+ type: :runtime
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '7.1'
132
+ - - "<"
133
+ - !ruby/object:Gem::Version
134
+ version: '9'
135
+ description: Mix Calculable into any model to get effective-dated, versioned formulas,
136
+ apportionment and aggregation helpers, and Liquid-rendered output — reusable across
137
+ payroll, e-commerce, and insurance domains.
138
+ email:
139
+ - lautarograciani2106@gmail.com
140
+ executables: []
141
+ extensions: []
142
+ extra_rdoc_files: []
143
+ files:
144
+ - ".rspec"
145
+ - ".rubocop.yml"
146
+ - CODE_OF_CONDUCT.md
147
+ - LICENSE.txt
148
+ - README.md
149
+ - Rakefile
150
+ - app/controllers/acts_as_calculator/application_controller.rb
151
+ - app/controllers/acts_as_calculator/formula_versions_controller.rb
152
+ - app/controllers/acts_as_calculator/formulas_controller.rb
153
+ - app/controllers/acts_as_calculator/imports_controller.rb
154
+ - app/controllers/acts_as_calculator/templates_controller.rb
155
+ - app/models/acts_as_calculator/formula.rb
156
+ - app/models/acts_as_calculator/formula_version.rb
157
+ - app/models/acts_as_calculator/lookup_table.rb
158
+ - app/models/acts_as_calculator/lookup_table_entry.rb
159
+ - app/models/acts_as_calculator/record.rb
160
+ - app/models/acts_as_calculator/run.rb
161
+ - app/models/acts_as_calculator/template.rb
162
+ - app/models/acts_as_calculator/variable.rb
163
+ - config/routes.rb
164
+ - lib/acts_as_calculator.rb
165
+ - lib/acts_as_calculator/aggregate_results.rb
166
+ - lib/acts_as_calculator/aggregation.rb
167
+ - lib/acts_as_calculator/apportion_amount.rb
168
+ - lib/acts_as_calculator/apportionment.rb
169
+ - lib/acts_as_calculator/build_calculator.rb
170
+ - lib/acts_as_calculator/build_lookups.rb
171
+ - lib/acts_as_calculator/calculable.rb
172
+ - lib/acts_as_calculator/calculator_cache.rb
173
+ - lib/acts_as_calculator/cast_date.rb
174
+ - lib/acts_as_calculator/cast_decimal.rb
175
+ - lib/acts_as_calculator/cast_json_safe.rb
176
+ - lib/acts_as_calculator/cast_liquid_value.rb
177
+ - lib/acts_as_calculator/cast_variable_attributes.rb
178
+ - lib/acts_as_calculator/configuration.rb
179
+ - lib/acts_as_calculator/distribute_remainder.rb
180
+ - lib/acts_as_calculator/divide_proportionally.rb
181
+ - lib/acts_as_calculator/engine.rb
182
+ - lib/acts_as_calculator/errors.rb
183
+ - lib/acts_as_calculator/evaluate_expression.rb
184
+ - lib/acts_as_calculator/evaluate_formula.rb
185
+ - lib/acts_as_calculator/find_lookup_table_references.rb
186
+ - lib/acts_as_calculator/find_owned_record.rb
187
+ - lib/acts_as_calculator/find_tier.rb
188
+ - lib/acts_as_calculator/formula_version_drop.rb
189
+ - lib/acts_as_calculator/function_registry.rb
190
+ - lib/acts_as_calculator/import_definitions.rb
191
+ - lib/acts_as_calculator/import_formula.rb
192
+ - lib/acts_as_calculator/import_lookup_table.rb
193
+ - lib/acts_as_calculator/import_outcome.rb
194
+ - lib/acts_as_calculator/import_summary.rb
195
+ - lib/acts_as_calculator/import_template.rb
196
+ - lib/acts_as_calculator/liquid_filters.rb
197
+ - lib/acts_as_calculator/persist_run.rb
198
+ - lib/acts_as_calculator/promote_template.rb
199
+ - lib/acts_as_calculator/publish_formula_version.rb
200
+ - lib/acts_as_calculator/publish_template.rb
201
+ - lib/acts_as_calculator/read_import_file.rb
202
+ - lib/acts_as_calculator/render_liquid.rb
203
+ - lib/acts_as_calculator/render_template.rb
204
+ - lib/acts_as_calculator/resolve_formula_version.rb
205
+ - lib/acts_as_calculator/resolve_import_owner.rb
206
+ - lib/acts_as_calculator/resolve_template.rb
207
+ - lib/acts_as_calculator/resolve_variables.rb
208
+ - lib/acts_as_calculator/result.rb
209
+ - lib/acts_as_calculator/result_drop.rb
210
+ - lib/acts_as_calculator/serialize_formula.rb
211
+ - lib/acts_as_calculator/serialize_formula_version.rb
212
+ - lib/acts_as_calculator/serialize_import_summary.rb
213
+ - lib/acts_as_calculator/serialize_template.rb
214
+ - lib/acts_as_calculator/supersede_formula_versions.rb
215
+ - lib/acts_as_calculator/tier.rb
216
+ - lib/acts_as_calculator/variable_spec.rb
217
+ - lib/acts_as_calculator/version.rb
218
+ - lib/generators/acts_as_calculator/import/import_generator.rb
219
+ - lib/generators/acts_as_calculator/install/install_generator.rb
220
+ - lib/generators/acts_as_calculator/install/templates/create_acts_as_calculator_tables.rb.tt
221
+ - lib/tasks/acts_as_calculator.rake
222
+ - sig/acts_as_calculator.rbs
223
+ homepage: https://github.com/lautarograc/acts_as_calculator
224
+ licenses:
225
+ - MIT
226
+ metadata:
227
+ rubygems_mfa_required: 'true'
228
+ homepage_uri: https://github.com/lautarograc/acts_as_calculator
229
+ source_code_uri: https://github.com/lautarograc/acts_as_calculator
230
+ changelog_uri: https://github.com/lautarograc/acts_as_calculator/blob/main/CHANGELOG.md
231
+ bug_tracker_uri: https://github.com/lautarograc/acts_as_calculator/issues
232
+ post_install_message:
233
+ rdoc_options: []
234
+ require_paths:
235
+ - lib
236
+ required_ruby_version: !ruby/object:Gem::Requirement
237
+ requirements:
238
+ - - ">="
239
+ - !ruby/object:Gem::Version
240
+ version: 3.2.0
241
+ required_rubygems_version: !ruby/object:Gem::Requirement
242
+ requirements:
243
+ - - ">="
244
+ - !ruby/object:Gem::Version
245
+ version: '0'
246
+ requirements: []
247
+ rubygems_version: 3.5.16
248
+ signing_key:
249
+ specification_version: 4
250
+ summary: A pricing and calculation engine on top of Dentaku.
251
+ test_files: []