amoskeag-rb 0.1.1c

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dbaa0e7ea45334ed0a0e3963aacc1f4c37183ab440a64ce1434f5973d1978b66
4
+ data.tar.gz: e65ac6e2c7cf6ee14a0907021847116f4f2ceea86b7214d9fd2e0a5073a8fe44
5
+ SHA512:
6
+ metadata.gz: 686fcac6a64a05575ebbefb37381dcf8faadac4cd20866a438cc5fd9fb7036e01e2019c3a2387d9bf125e2c3f4789e502d87ff3b9f87a349bac55b8cb79f79f2
7
+ data.tar.gz: 916788a2f717bbea591429ff371cc8dd6404bc7ec7e778aca98ee119d6b0b396ddce16685a032a3fa9893aab78ecee8bd4f7ecb75f7c84fd4f220446e4b2c2b1
data/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to the amoskeag-rb gem will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2025-01-20
9
+
10
+ ### Added
11
+ - Initial release of amoskeag-rb gem
12
+ - Native Ruby bindings to Amoskeag DSL
13
+ - FFI layer using statically compiled Rust library
14
+ - Core API methods:
15
+ - `Amoskeag.compile(source, symbols)` - Compile programs with symbol validation
16
+ - `Amoskeag.evaluate(program, data)` - Evaluate compiled programs
17
+ - `Amoskeag.eval_expression(source, data, symbols)` - Compile and evaluate in one step
18
+ - Full support for all Amoskeag data types:
19
+ - Numbers, Strings, Booleans, Nil
20
+ - Arrays and Dictionaries
21
+ - Symbols with compile-time validation
22
+ - Ruby-friendly API with automatic type conversion
23
+ - Thread-safe compiled programs
24
+ - Comprehensive error handling with CompileError and EvalError
25
+ - Complete documentation and examples
26
+ - JSON-based marshalling between Ruby and native code
27
+
28
+ ### Features
29
+ - Business Rules Engine capabilities
30
+ - Template Engine functionality
31
+ - Spreadsheet Formula support
32
+ - 60+ standard library functions
33
+ - Excel-compatible financial functions
34
+ - Safe navigation (nil-safe property access)
35
+ - Pure functional evaluation (no side effects)
36
+ - Security-first design (immune to code injection)
37
+
38
+ [0.1.0]: https://github.com/durable-oss/amoskeag-rb/releases/tag/v0.1.0
data/README.md ADDED
@@ -0,0 +1,335 @@
1
+ # Amoskeag Ruby Gem
2
+
3
+ Native Ruby bindings for [Amoskeag](https://github.com/durable-oss/amoskeag) - a secure, purely functional DSL for business rules, templates, and spreadsheet formulas.
4
+
5
+ ## Features
6
+
7
+ - **Security-First Design**: Immune to code injection attacks (SSTI, RCE)
8
+ - **Purely Functional**: No side effects, no mutation, no I/O
9
+ - **Static Validation**: Symbols and functions validated at compile-time
10
+ - **High Performance**: Native Rust implementation with zero-copy FFI
11
+ - **Rich Standard Library**: 60+ built-in functions for strings, numbers, collections, and finance
12
+ - **Multiple Use Cases**:
13
+ - Business Rules Engine (insurance, loans, eligibility)
14
+ - Template Engine (secure alternative to ERB)
15
+ - Spreadsheet Formulas (Excel-compatible financial functions)
16
+
17
+ ## Installation
18
+
19
+ ### Prerequisites
20
+
21
+ - Ruby 2.7 or higher
22
+ - Rust and Cargo (for building the native extension)
23
+
24
+ ### Install from source
25
+
26
+ ```bash
27
+ gem build amoskeag-rb.gemspec
28
+ gem install amoskeag-rb-0.1.0.gem
29
+ ```
30
+
31
+ Or add to your Gemfile:
32
+
33
+ ```ruby
34
+ gem 'amoskeag-rb', path: 'path/to/amoskeag-rb'
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```ruby
40
+ require 'amoskeag-rb'
41
+
42
+ # Basic arithmetic
43
+ Amoskeag.eval_expression("2 + 2", {})
44
+ # => 4.0
45
+
46
+ # Using variables
47
+ Amoskeag.eval_expression("user.age * 2", { "user" => { "age" => 25 } })
48
+ # => 50.0
49
+
50
+ # String operations with pipe
51
+ Amoskeag.eval_expression('"hello world" | upcase', {})
52
+ # => "HELLO WORLD"
53
+
54
+ # Business rules with symbols
55
+ code = "if user.age >= 18 :adult else :minor end"
56
+ Amoskeag.eval_expression(code, { "user" => { "age" => 25 } }, [:adult, :minor])
57
+ # => :adult
58
+ ```
59
+
60
+ ## Core Concepts
61
+
62
+ ### Compile Once, Evaluate Many
63
+
64
+ For best performance, compile programs once and evaluate them multiple times:
65
+
66
+ ```ruby
67
+ # Compile the program (with symbol validation)
68
+ program = Amoskeag.compile(
69
+ "if score >= 90 :A else :B end",
70
+ [:A, :B, :C, :D, :F]
71
+ )
72
+
73
+ # Evaluate with different data
74
+ Amoskeag.evaluate(program, { "score" => 95 }) # => :A
75
+ Amoskeag.evaluate(program, { "score" => 85 }) # => :B
76
+ ```
77
+
78
+ ### Data Types
79
+
80
+ Amoskeag supports seven fundamental types:
81
+
82
+ ```ruby
83
+ # Numbers (64-bit float)
84
+ Amoskeag.eval_expression("42", {}) # => 42.0
85
+
86
+ # Strings
87
+ Amoskeag.eval_expression('"hello"', {}) # => "hello"
88
+
89
+ # Booleans
90
+ Amoskeag.eval_expression("true and false", {}) # => false
91
+
92
+ # Nil
93
+ Amoskeag.eval_expression("nil", {}) # => nil
94
+
95
+ # Arrays
96
+ Amoskeag.eval_expression("[1, 2, 3]", {}) # => [1.0, 2.0, 3.0]
97
+
98
+ # Dictionaries (hashes)
99
+ Amoskeag.eval_expression('{"name": "Alice", "age": 30}', {})
100
+ # => {"name" => "Alice", "age" => 30.0}
101
+
102
+ # Symbols (validated at compile-time)
103
+ Amoskeag.eval_expression(":approved", {}, [:approved, :denied])
104
+ # => :approved
105
+ ```
106
+
107
+ ### Safe Navigation
108
+
109
+ Missing keys return `nil` instead of raising errors:
110
+
111
+ ```ruby
112
+ Amoskeag.eval_expression("user.address.street", { "user" => {} })
113
+ # => nil
114
+ ```
115
+
116
+ ## Examples
117
+
118
+ ### Business Rules Engine
119
+
120
+ ```ruby
121
+ # Define eligibility rules
122
+ rules = <<~AMOSKEAG
123
+ let applicant = {
124
+ "age": user.age,
125
+ "state": user.state,
126
+ "credit_score": user.credit_score
127
+ }
128
+ in let restricted_states = ["FL", "LA", "TX"]
129
+ in
130
+ if contains(restricted_states, applicant.state)
131
+ :deny
132
+ else if applicant.age < 18
133
+ :deny
134
+ else if applicant.credit_score < 650
135
+ :conditional
136
+ else
137
+ :approve
138
+ end
139
+ AMOSKEAG
140
+
141
+ # Compile once
142
+ program = Amoskeag.compile(rules, [:approve, :deny, :conditional])
143
+
144
+ # Evaluate for different users
145
+ user1 = { "age" => 25, "state" => "CA", "credit_score" => 720 }
146
+ Amoskeag.evaluate(program, { "user" => user1 }) # => :approve
147
+
148
+ user2 = { "age" => 30, "state" => "FL", "credit_score" => 750 }
149
+ Amoskeag.evaluate(program, { "user" => user2 }) # => :deny
150
+ ```
151
+
152
+ ### Template Engine
153
+
154
+ ```ruby
155
+ template = <<~AMOSKEAG
156
+ "Hello, " + user.name + "! " +
157
+ if user.premium
158
+ "Welcome to Premium. "
159
+ else
160
+ "Upgrade to Premium today! "
161
+ end +
162
+ "You have " + user.messages | string + " new messages."
163
+ AMOSKEAG
164
+
165
+ program = Amoskeag.compile(template, [])
166
+
167
+ data = {
168
+ "user" => {
169
+ "name" => "Alice",
170
+ "premium" => true,
171
+ "messages" => 5
172
+ }
173
+ }
174
+
175
+ Amoskeag.evaluate(program, data)
176
+ # => "Hello, Alice! Welcome to Premium. You have 5 new messages."
177
+ ```
178
+
179
+ ### Financial Calculations
180
+
181
+ ```ruby
182
+ # Monthly payment for a $250,000 loan at 4.5% APR for 30 years
183
+ formula = "pmt(rate / 12, years * 12, -principal) | round(2)"
184
+ program = Amoskeag.compile(formula, [])
185
+
186
+ data = {
187
+ "rate" => 0.045,
188
+ "years" => 30,
189
+ "principal" => 250000
190
+ }
191
+
192
+ Amoskeag.evaluate(program, data)
193
+ # => 1266.71
194
+ ```
195
+
196
+ ### Array and Collection Operations
197
+
198
+ ```ruby
199
+ # Calculate average of filtered values
200
+ code = <<~AMOSKEAG
201
+ let nums = [95, 82, 67, 88, 91, 73]
202
+ in let passing = nums | filter(lambda(x) { x >= 70 })
203
+ in passing | avg | round(2)
204
+ AMOSKEAG
205
+
206
+ Amoskeag.eval_expression(code, {})
207
+ # => 85.8
208
+ ```
209
+
210
+ ## Standard Library
211
+
212
+ Amoskeag includes 60+ built-in functions organized into categories:
213
+
214
+ ### String Functions
215
+ - `upcase`, `downcase`, `capitalize`
216
+ - `strip`, `lstrip`, `rstrip`
217
+ - `split`, `join`, `replace`
218
+ - `truncate`, `prepend`, `append`
219
+
220
+ ### Numeric Functions
221
+ - `abs`, `ceil`, `floor`, `round`
222
+ - `max`, `min`, `clamp`
223
+ - `plus`, `minus`, `times`, `divided_by`
224
+
225
+ ### Collection Functions
226
+ - `size`, `first`, `last`, `at`
227
+ - `contains`, `sort`, `reverse`
228
+ - `sum`, `avg`, `max`, `min`
229
+ - `keys`, `values`
230
+
231
+ ### Logic Functions
232
+ - `if_then_else`, `choose`
233
+ - `is_number`, `is_string`, `is_boolean`, `is_nil`, `is_array`, `is_dictionary`
234
+ - `coalesce`, `default`
235
+
236
+ ### Financial Functions (Excel-compatible)
237
+ - **Time Value**: `pmt`, `pv`, `fv`, `nper`, `rate`
238
+ - **Investment**: `npv`, `irr`, `mirr`
239
+ - **Depreciation**: `sln`, `ddb`, `db`
240
+ - **Payment Components**: `ipmt`, `ppmt`, `cumipmt`, `cumprinc`
241
+
242
+ ## Error Handling
243
+
244
+ ```ruby
245
+ begin
246
+ # Undefined symbol will raise CompileError
247
+ Amoskeag.compile(":invalid_symbol", [:valid, :symbols])
248
+ rescue Amoskeag::CompileError => e
249
+ puts "Compilation failed: #{e.message}"
250
+ end
251
+
252
+ begin
253
+ # Missing variable will raise EvalError
254
+ program = Amoskeag.compile("missing_var", [])
255
+ Amoskeag.evaluate(program, {})
256
+ rescue Amoskeag::EvalError => e
257
+ puts "Evaluation failed: #{e.message}"
258
+ end
259
+ ```
260
+
261
+ ## Performance Tips
262
+
263
+ 1. **Compile once, evaluate many**: Compilation has overhead, so reuse compiled programs
264
+ 2. **Use native types**: Ruby Symbols map directly to Amoskeag Symbols with zero overhead
265
+ 3. **Keep data shallow**: Deep nesting requires more JSON serialization
266
+ 4. **Avoid string concatenation in loops**: Use `join` function instead
267
+
268
+ ## Thread Safety
269
+
270
+ Compiled programs are immutable and thread-safe. You can safely evaluate the same program from multiple threads concurrently:
271
+
272
+ ```ruby
273
+ program = Amoskeag.compile("x * 2", [])
274
+
275
+ threads = 10.times.map do |i|
276
+ Thread.new do
277
+ Amoskeag.evaluate(program, { "x" => i })
278
+ end
279
+ end
280
+
281
+ results = threads.map(&:value)
282
+ # => [0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0]
283
+ ```
284
+
285
+ ## Building from Source
286
+
287
+ ```bash
288
+ # Clone the repository
289
+ git clone https://github.com/durable-oss/amoskeag-rb.git
290
+ cd amoskeag-rb
291
+
292
+ # Build and install the gem
293
+ gem build amoskeag-rb.gemspec
294
+ gem install amoskeag-rb-0.1.0.gem
295
+ ```
296
+
297
+ ### Development
298
+
299
+ ```bash
300
+ # Build the native extension
301
+ cd amoskeag
302
+ ruby extconf.rb
303
+ make
304
+
305
+ # Run tests
306
+ rake test
307
+ ```
308
+
309
+ ## Architecture
310
+
311
+ The gem consists of four layers:
312
+
313
+ 1. **Rust Core**: Pure Rust implementation of the Amoskeag compiler and interpreter (from [durable-oss/amoskeag](https://github.com/durable-oss/amoskeag))
314
+ 2. **FFI Layer** (`amoskeag/src/lib.rs`): C-compatible FFI bindings using static library
315
+ 3. **Ruby Extension** (`amoskeag/amoskeag_native.c`): Native Ruby C extension
316
+ 4. **Ruby Wrapper** (`lib/amoskeag-rb.rb`): Idiomatic Ruby API with proper marshalling
317
+
318
+ Data flows through JSON serialization at the Ruby/C boundary for simplicity and type safety.
319
+
320
+ ## License
321
+
322
+ MIT
323
+
324
+ ## Contributing
325
+
326
+ Contributions are welcome! Please open issues or pull requests on the [GitHub repository](https://github.com/durable-oss/amoskeag-rb).
327
+
328
+ ## Support
329
+
330
+ - GitHub Issues: https://github.com/durable-oss/amoskeag-rb/issues
331
+ - Documentation: https://github.com/durable-oss/amoskeag-rb
332
+
333
+ ## Credits
334
+
335
+ Amoskeag is built by [Durable Programming](https://github.com/durable-oss) with a focus on security, correctness, and developer experience.
@@ -0,0 +1,10 @@
1
+ require 'mkmf'
2
+ require 'rb_sys/mkmf'
3
+
4
+ # Check for cargo
5
+ unless system("which cargo > /dev/null 2>&1")
6
+ abort "Cargo (Rust build tool) not found in PATH. Please install Rust from https://rustup.rs/"
7
+ end
8
+
9
+ # Create the Makefile using rb_sys
10
+ create_rust_makefile("amoskeag_native")
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Amoskeag
4
+ VERSION = "0.1.1c"
5
+ AMOSKEAG_VERSION = "0.1.1e"
6
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'amoskeag-rb/version'
5
+
6
+ # Load the native extension
7
+ begin
8
+ # Try relative path first (for development)
9
+ begin
10
+ require_relative '../lib/amoskeag_native'
11
+ rescue LoadError
12
+ # Fall back to standard require (for installed gem)
13
+ require 'amoskeag_native'
14
+ end
15
+ rescue LoadError => e
16
+ raise LoadError, "Failed to load amoskeag_native extension. " \
17
+ "Make sure the gem is properly installed and compiled. " \
18
+ "Original error: #{e.message}"
19
+ end
20
+
21
+ # Amoskeag - A secure, functional DSL for business rules
22
+ #
23
+ # The native extension defines:
24
+ # - Amoskeag::Error < StandardError
25
+ # - Amoskeag::CompileError < Amoskeag::Error
26
+ # - Amoskeag::EvalError < Amoskeag::Error
27
+ # - Amoskeag::Program (compiled program class)
28
+ # - Amoskeag.compile(source, symbols = []) -> Program
29
+ # - Amoskeag.evaluate(program, data) -> Object
30
+ # - Amoskeag.eval_expression(source, data, symbols = []) -> Object
31
+
32
+ module Amoskeag
33
+ class << self
34
+ # Alias native methods for potential future wrapper use
35
+ alias compile_native compile
36
+ alias evaluate_native evaluate
37
+ alias eval_expression_native eval_expression
38
+
39
+ # Unwrap symbols from their hash representation at the top level only
40
+ # This allows expression results like `:adult` to be returned as symbols
41
+ # while keeping symbols nested in data structures in wrapped format
42
+ def unwrap_symbols(value)
43
+ case value
44
+ when Hash
45
+ # Check if this is a wrapped symbol at the top level
46
+ if value.keys == ["__symbol__"]
47
+ value["__symbol__"].to_sym
48
+ else
49
+ # Don't unwrap nested symbols - they're part of data structures
50
+ value
51
+ end
52
+ else
53
+ value
54
+ end
55
+ end
56
+
57
+ # Recursively wrap symbols for native processing
58
+ def wrap_symbols(value)
59
+ case value
60
+ when Symbol
61
+ { "__symbol__" => value.to_s }
62
+ when Hash
63
+ value.transform_values { |v| wrap_symbols(v) }
64
+ when Array
65
+ value.map { |v| wrap_symbols(v) }
66
+ else
67
+ value
68
+ end
69
+ end
70
+
71
+ # Validate that data is JSON-serializable
72
+ def validate_data(data, path = "data")
73
+ case data
74
+ when String, Integer, Float, TrueClass, FalseClass, NilClass, Symbol
75
+ # These are valid types (note: not all Numeric, only Integer and Float)
76
+ data
77
+ when Hash
78
+ data.each do |key, value|
79
+ unless key.is_a?(String) || key.is_a?(Symbol)
80
+ raise ArgumentError, "#{path} key must be String or Symbol, got #{key.class}"
81
+ end
82
+ validate_data(value, "#{path}[#{key.inspect}]")
83
+ end
84
+ data
85
+ when Array
86
+ data.each_with_index do |item, idx|
87
+ validate_data(item, "#{path}[#{idx}]")
88
+ end
89
+ data
90
+ else
91
+ # Invalid type - include path information
92
+ raise ArgumentError, "#{path} contains invalid type #{data.class}"
93
+ end
94
+ end
95
+ end
96
+
97
+ # Override the compile method (no wrapping needed, just validation)
98
+ def self.compile(source, symbols = [])
99
+ compile_native(source, symbols)
100
+ end
101
+
102
+ # Override the evaluate method to wrap/unwrap symbols and validate data
103
+ def self.evaluate(program, data)
104
+ validate_data(data)
105
+ result = evaluate_native(program, data)
106
+ unwrap_symbols(result)
107
+ end
108
+
109
+ # Override the eval_expression method to wrap/unwrap symbols and validate data
110
+ def self.eval_expression(source, data, symbols = [])
111
+ validate_data(data)
112
+ result = eval_expression_native(source, data, symbols)
113
+ unwrap_symbols(result)
114
+ end
115
+
116
+ # Override Program.new to raise NoMethodError
117
+ class Program
118
+ def self.new(*)
119
+ raise NoMethodError, "undefined method `new' for Amoskeag::Program"
120
+ end
121
+ end
122
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amoskeag-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1c
5
+ platform: ruby
6
+ authors:
7
+ - Durable Programming
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-01 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: json
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rake-compiler
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.2'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.2'
54
+ - !ruby/object:Gem::Dependency
55
+ name: minitest
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '5.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: yard
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.9'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.9'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rb_sys
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.9'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.9'
96
+ description: |
97
+ Amoskeag is a purely functional, statically-validated Domain-Specific Language (DSL)
98
+ designed for high-security, sandboxed evaluation. It's perfect for:
99
+
100
+ - Business Rules Engines (insurance underwriting, loan approval)
101
+ - Template Engines (secure alternative to ERB with more power than Liquid)
102
+ - Spreadsheet Formula Engines (Excel-like calculations)
103
+
104
+ This gem provides native Ruby bindings to the Amoskeag library, compiled from Rust
105
+ for maximum performance and security.
106
+ email:
107
+ - contact@example.com
108
+ executables: []
109
+ extensions:
110
+ - ext/amoskeag/extconf.rb
111
+ extra_rdoc_files: []
112
+ files:
113
+ - CHANGELOG.md
114
+ - README.md
115
+ - ext/amoskeag/extconf.rb
116
+ - lib/amoskeag-rb.rb
117
+ - lib/amoskeag-rb/version.rb
118
+ homepage: https://github.com/durable-oss/amoskeag-rb
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ homepage_uri: https://github.com/durable-oss/amoskeag-rb
123
+ source_code_uri: https://github.com/durable-oss/amoskeag-rb
124
+ changelog_uri: https://github.com/durable-oss/amoskeag-rb/blob/main/CHANGELOG.md
125
+ post_install_message: |2+
126
+
127
+ Thank you for installing amoskeag-rb!
128
+
129
+ Amoskeag is a secure, purely functional DSL for business rules, templates,
130
+ and spreadsheet formulas. It's designed to be immune to code injection
131
+ attacks while providing powerful expression evaluation capabilities.
132
+
133
+ Get started:
134
+ require 'amoskeag-rb'
135
+ result = Amoskeag.eval_expression("2 + 2", {}) # => 4.0
136
+
137
+ Documentation: https://github.com/durable-oss/amoskeag-rb
138
+
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 2.7.0
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubygems_version: 3.6.9
154
+ specification_version: 4
155
+ summary: Ruby bindings for Amoskeag - a secure, functional DSL for business rules
156
+ test_files: []
157
+ ...