introhive_expression_language 0.6.8

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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +80 -0
  3. data/.github/pull_request_template.md +17 -0
  4. data/.github/workflows/ci.yml +31 -0
  5. data/.gitignore +15 -0
  6. data/.qlty/qlty.toml +10 -0
  7. data/.ruby-version +1 -0
  8. data/CLAUDE.md +169 -0
  9. data/Gemfile +4 -0
  10. data/Gemfile.lock +87 -0
  11. data/README.md +55 -0
  12. data/Rakefile +10 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/introhive_expression_language.gemspec +54 -0
  16. data/lib/introhive_expression_language/iel/evaluation_context.rb +35 -0
  17. data/lib/introhive_expression_language/iel/evaluation_error.rb +9 -0
  18. data/lib/introhive_expression_language/iel/evaluator.rb +166 -0
  19. data/lib/introhive_expression_language/iel/node_util.rb +65 -0
  20. data/lib/introhive_expression_language/iel/parser.rb +30 -0
  21. data/lib/introhive_expression_language/iel/sexp_parser.rb +339 -0
  22. data/lib/introhive_expression_language/iel/std_lib.rb +43 -0
  23. data/lib/introhive_expression_language/iel/std_lib_assoc.rb +84 -0
  24. data/lib/introhive_expression_language/iel/std_lib_control.rb +81 -0
  25. data/lib/introhive_expression_language/iel/std_lib_enum.rb +30 -0
  26. data/lib/introhive_expression_language/iel/std_lib_existence.rb +19 -0
  27. data/lib/introhive_expression_language/iel/std_lib_json.rb +38 -0
  28. data/lib/introhive_expression_language/iel/std_lib_kind.rb +88 -0
  29. data/lib/introhive_expression_language/iel/std_lib_let.rb +22 -0
  30. data/lib/introhive_expression_language/iel/std_lib_list.rb +85 -0
  31. data/lib/introhive_expression_language/iel/std_lib_logic.rb +52 -0
  32. data/lib/introhive_expression_language/iel/std_lib_math.rb +75 -0
  33. data/lib/introhive_expression_language/iel/std_lib_number.rb +28 -0
  34. data/lib/introhive_expression_language/iel/std_lib_regexp.rb +30 -0
  35. data/lib/introhive_expression_language/iel/std_lib_string.rb +79 -0
  36. data/lib/introhive_expression_language/iel/symbol_detail.rb +16 -0
  37. data/lib/introhive_expression_language/iel.rb +2 -0
  38. data/lib/introhive_expression_language/version.rb +3 -0
  39. data/lib/introhive_expression_language.rb +9 -0
  40. metadata +305 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f1f4e06a586216b01fecc712235431ebee04bd202e3b80857599c4fa3582e55c
4
+ data.tar.gz: 67404a7af0a9e9618dfb10e92dd9cbb086d3b9953512cc15bb2f737c8b5473ef
5
+ SHA512:
6
+ metadata.gz: ef30de77075f6c5daf27c9c0f430e286bd4100ef625dc0ee8f9a1de661cf8bc999139f8ed1df3c2561ccad338cca83b2925719d442460b78b07752611555992b
7
+ data.tar.gz: ee90bdc99822ecb03e8d8c7ce22637dc5f9535881981cf584b3959262d6cdfa808a490d0fc78c81d040d3d6a8c467ba19efeea2004952b819c67f3b5a8d26314
@@ -0,0 +1,80 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "github-actions"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
12
+
13
+ - package-ecosystem: "npm"
14
+ directory: "/"
15
+ open-pull-requests-limit: 0
16
+ schedule:
17
+ interval: "weekly"
18
+ groups:
19
+ npm-minor-patch:
20
+ applies-to: "security-updates"
21
+ update-types: ["minor", "patch"]
22
+ npm-dev-dependencies:
23
+ applies-to: "security-updates"
24
+ dependency-type: "development"
25
+
26
+ - package-ecosystem: "bundler"
27
+ directory: "/"
28
+ open-pull-requests-limit: 0
29
+ schedule:
30
+ interval: "weekly"
31
+ groups:
32
+ bundler-minor-patch:
33
+ applies-to: "security-updates"
34
+ update-types: ["minor", "patch"]
35
+
36
+ - package-ecosystem: "nuget"
37
+ directory: "/"
38
+ open-pull-requests-limit: 0
39
+ schedule:
40
+ interval: "weekly"
41
+ groups:
42
+ nuget-minor-patch:
43
+ applies-to: "security-updates"
44
+ update-types: ["minor", "patch"]
45
+
46
+ - package-ecosystem: "gomod"
47
+ directory: "/"
48
+ open-pull-requests-limit: 0
49
+ schedule:
50
+ interval: "weekly"
51
+ groups:
52
+ gomod-minor-patch:
53
+ applies-to: "security-updates"
54
+ update-types: ["minor", "patch"]
55
+
56
+ - package-ecosystem: "pip"
57
+ directory: "/"
58
+ open-pull-requests-limit: 0
59
+ schedule:
60
+ interval: "weekly"
61
+ groups:
62
+ pip-minor-patch:
63
+ applies-to: "security-updates"
64
+ update-types: ["minor", "patch"]
65
+ pip-dev-dependencies:
66
+ applies-to: "security-updates"
67
+ dependency-type: "development"
68
+
69
+ - package-ecosystem: "uv"
70
+ directory: "/"
71
+ open-pull-requests-limit: 0
72
+ schedule:
73
+ interval: "weekly"
74
+ groups:
75
+ uv-minor-patch:
76
+ applies-to: "security-updates"
77
+ update-types: ["minor", "patch"]
78
+ uv-dev-dependencies:
79
+ applies-to: "security-updates"
80
+ dependency-type: "development"
@@ -0,0 +1,17 @@
1
+ ### Summary of Changes
2
+
3
+ <!-- Include brief description of changes, and explanation of the business problem they solve. -->
4
+
5
+ **JIRA Link**: https://introhive.atlassian.net/browse/IHS- <!-- Update this! -->
6
+
7
+ ### Testing Steps
8
+
9
+ <!-- Include brief description of how to test the code changes if needed -->
10
+
11
+ ### Review Checklist
12
+ *To be completed by the reviewer.
13
+
14
+ - [ ] All affected code paths have been tested locally by the reviewer where possible.
15
+ - [ ] Unit/functional test coverage is adequate.
16
+ - [ ] Version updated if the current version is already in use. (version: x.y.z, x = breaking changes, y = new functionality, and z = backwards compatible bug fixes)
17
+ - [ ] Approved for merge by a member of Suggestion Service team
@@ -0,0 +1,31 @@
1
+ name: CI
2
+
3
+ # Run tests on push and pull requests
4
+ on:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ name: Test
10
+ runs-on: ubuntu-latest
11
+
12
+ # Set minimal permissions for the GITHUB_TOKEN
13
+ permissions:
14
+ contents: read
15
+
16
+ steps:
17
+ # Check out the repository code
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ # Set up Ruby using the version from .ruby-version file
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ bundler: 4.0.12
26
+ # Automatically runs bundle install and caches gems
27
+ bundler-cache: true
28
+
29
+ # Run the test suite
30
+ - name: Run tests
31
+ run: bundle exec rake test
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.idea/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .DS_Store
11
+ /vendor/bundle/
12
+ # Ignore everything in .qlty/
13
+ .qlty/*
14
+ # Except qlty.toml
15
+ !.qlty/qlty.toml
data/.qlty/qlty.toml ADDED
@@ -0,0 +1,10 @@
1
+ config_version = "0"
2
+ # First, use the built-in Qlty source
3
+ [[source]]
4
+ name = "default"
5
+ default = true
6
+
7
+ [[source]]
8
+ name = "Introhive"
9
+ repository = "git@github.com:Introhive/qlty-configs.git"
10
+ branch = "master"
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.4
data/CLAUDE.md ADDED
@@ -0,0 +1,169 @@
1
+ # introhive_expression_language
2
+
3
+ ## Project Overview
4
+
5
+ IEL (Introhive Expression Language) is a Ruby gem implementing an embeddable, sandboxed programming language for end-user expression evaluation. It is designed to be safe for end users to author expressions inside Introhive's platform — they cannot escape the sandbox or call arbitrary Ruby.
6
+
7
+ The language is Lisp-inspired: all expressions are s-expressions delimited by `[]`, functions are first-class, and evaluation is purely functional. Users can define their own functions via `def` and compose them with a rich standard library.
8
+
9
+ IEL is the foundation that `introhive_templating_language` (ITL) builds on. The gem exposes `Platform::IEL::Evaluator` as its primary interface, which accepts an expression string and an `EvaluationContext` containing the symbols and functions available to the expression.
10
+
11
+ ## Project Structure
12
+
13
+ - `lib/introhive_expression_language/` — All gem source code
14
+ - `iel.rb` — Top-level require: loads `StdLib` and `Evaluator`
15
+ - `iel/sexp_parser.rb` — Lexer + parser; produces `SexpParser::Node` AST nodes
16
+ - `iel/parser.rb` — Post-parse transforms (e.g. quote sugar `'x` → `[quote x]`)
17
+ - `iel/evaluator.rb` — Tree-walking evaluator and `wrap_native_function` helper
18
+ - `iel/evaluation_context.rb` — Scoped symbol table (supports nested/enclosing contexts)
19
+ - `iel/evaluation_error.rb` — Runtime error type
20
+ - `iel/symbol_detail.rb` — Symbol metadata helpers
21
+ - `iel/node_util.rb` — Node utility helpers
22
+ - `iel/std_lib.rb` — Aggregates all standard library modules
23
+ - `iel/std_lib_*.rb` — Standard library by domain (math, string, list, logic, control, etc.)
24
+ - `test/iel/` — Minitest tests mirroring `lib/` structure (one `*_test.rb` per source file)
25
+ - `test/test_helper.rb` — Test setup: requires gem, minitest, shoulda, mocha, pry
26
+
27
+ ## Core Principles
28
+
29
+ 1. **Every value is a Node**: All data flowing through evaluation is a `SexpParser::Node`. Never pass raw Ruby scalars between IEL functions — wrap them.
30
+ 2. **Contexts are scoped, not mutated**: Create a child `EvaluationContext` when entering a function call scope; write to `enclosing_context` when `let`/`def` should escape the current scope.
31
+ 3. **`||=` guards in stdlib declarations**: Each `declare_*` method uses `||=` so that a host application can pre-populate the context with overrides before declaring the stdlib.
32
+ 4. **Argument suffixes carry semantics**: Parameters ending in `__` are passed unevaluated (lazy/quoted). Varargs are named with a `va_` prefix; `va_foo__` means varargs + unevaluated.
33
+ 5. **Tests cover behavior, not implementation**: Test files assert on evaluated results; they do not reach into parser internals unless testing the parser specifically.
34
+
35
+ ## Development Commands
36
+
37
+ ### Setup
38
+ ```bash
39
+ bin/setup # installs dependencies via bundler
40
+ ```
41
+
42
+ ### Interactive Console
43
+ ```bash
44
+ bin/console # pry session with the gem loaded
45
+ ```
46
+
47
+ ### Testing
48
+ ```bash
49
+ rake test # run all tests
50
+ ruby -Ilib:test test/iel/evaluator_test.rb # run a single test file
51
+ ```
52
+
53
+ ### Linting
54
+ ```bash
55
+ bundle exec rubocop # lint (rubocop 0.83 + rails + performance)
56
+ ```
57
+
58
+ ### Release
59
+ ```bash
60
+ # 1. Bump version in lib/introhive_expression_language/version.rb
61
+ bundle exec rake release # tags, pushes commits + tags, pushes .gem
62
+ ```
63
+
64
+ ## Versioning
65
+
66
+ Any change to the gem (including dependency bumps) requires a version bump in [lib/introhive_expression_language/version.rb](lib/introhive_expression_language/version.rb).
67
+
68
+ Version format: `x.y.z`
69
+ - `x` — breaking changes (removed/changed public API)
70
+ - `y` — new backwards-compatible functionality (existing expressions and integrations continue to work unchanged; callers just gain access to something new)
71
+ - `z` — backwards-compatible bug fixes, dependency bumps, tooling/infrastructure changes
72
+
73
+ ### When to bump each segment
74
+
75
+ | Change type | Segment |
76
+ |---|---|
77
+ | Removed or changed `Evaluator`, `EvaluationContext`, or `StdLib` public API | `x` (major) |
78
+ | New stdlib functions (e.g. adding `string-reverse` to `StdLibString`) | `y` (minor) |
79
+ | New evaluator feature that doesn't break existing expressions | `y` (minor) |
80
+ | New public Ruby API on `Evaluator` or `EvaluationContext` | `y` (minor) |
81
+ | Bug fixes, dependency updates, Ruby version bumps, dev tooling | `z` (patch) |
82
+
83
+ ### Steps
84
+
85
+ 1. Increment the version in `lib/introhive_expression_language/version.rb`
86
+ 2. Run `bundle install` to update the `BUNDLED WITH` entry in `Gemfile.lock`
87
+ 3. Commit both files together in a single version bump commit
88
+ 4. Run `bundle exec rake release` to tag, push commits + tags, and push the `.gem`
89
+
90
+ ### Downstream
91
+
92
+ Once the version bump is merged, a corresponding PR in the `introhive_templating_language` repo is required to update its reference to the new `introhive_expression_language` version. Do not deploy the downstream bump until the new gem version is available.
93
+
94
+ ## Testing Conventions
95
+
96
+ - **Framework**: Minitest with `shoulda-context` (`should '...' do`) and `mocha` for mocking
97
+ - **Organization**: One test file per source file, all under `test/iel/`
98
+ - **Test helper**: `test/test_helper.rb` — always required first; provides `assert_raise_with_message`
99
+ - **Guidelines**:
100
+ - Build AST nodes directly with `SexpParser::Node.*` factory methods for assertions
101
+ - Use `StdLib.new_context` when the test needs standard library functions; use a bare `EvaluationContext.new` when testing evaluation in isolation
102
+ - Test error messages exactly with `assert_raise_with_message(EvaluationError, "...")`
103
+ - Do not mock `Evaluator` or `SexpParser` internals — test through the public `eval_expr` / `eval_block_expr` API
104
+
105
+ ## Component Guide
106
+
107
+ ### SexpParser (`iel/sexp_parser.rb`)
108
+
109
+ **What it is**: Lexer + recursive-descent parser that converts an IEL source string into a tree of `SexpParser::Node` objects.
110
+
111
+ **Node kinds**: `:list`, `:symbol`, `:string_literal`, `:numeric_literal`, `:boolean`, `:nil`, `:nan`, `:native_function`
112
+
113
+ **Key patterns**:
114
+ - Parse via `SexpParser.parse(expr)` — returns the root `Node`
115
+ - Construct test nodes with factory methods: `Node.string_literal("x")`, `Node.numeric_literal(1)`, `Node.list([...])`, `Node.symbol("name")`
116
+ - Source positions are character offsets into the original string; `node.source_desc` renders a human-readable line/column pointer
117
+
118
+ ### Parser (`iel/parser.rb`)
119
+
120
+ **What it is**: A thin post-processing pass over the raw s-expression AST. Currently its only job is desugaring quote syntax: `'x` → `[quote x]`.
121
+
122
+ **Key patterns**:
123
+ - Always call `Parser.parse(expr)` rather than `SexpParser.parse` directly — it runs the transforms
124
+ - `Evaluator.eval_expr` calls `Parser.parse` internally, so callers never need to invoke the parser directly
125
+
126
+ ### Evaluator (`iel/evaluator.rb`)
127
+
128
+ **What it is**: A tree-walking evaluator. Entry points are `eval_expr(expr_string, ctx)` and `eval_block_expr(expr_string, ctx)`.
129
+
130
+ **Key patterns**:
131
+ - `eval_expr` evaluates a single expression and returns a `Node`
132
+ - `eval_block_expr` evaluates each top-level form in order and returns the last result (used by `def` bodies)
133
+ - `wrap_native_function(&block)` registers a Ruby lambda as a callable IEL function; param names are introspected to build the IEL argument list
134
+ - Arguments whose Ruby param name ends in `__` are not pre-evaluated before being passed to the native function
135
+
136
+ ### EvaluationContext (`iel/evaluation_context.rb`)
137
+
138
+ **What it is**: A scoped symbol table. Contexts chain via `enclosing_context`, forming a lookup chain from innermost to outermost scope.
139
+
140
+ **Key patterns**:
141
+ - `ctx['symbol']` walks the chain; `ctx['symbol'] = node` writes only to the current scope
142
+ - Symbols prefixed `C_` are constants and raise on reassignment
143
+ - `EvaluationContext.new(parent_ctx)` creates a child scope (used automatically during function calls)
144
+ - `ctx.root_context` traverses to the outermost context
145
+
146
+ ### Standard Library (`iel/std_lib_*.rb`)
147
+
148
+ **What it is**: IEL built-in functions, split into domain modules. Each module has a `declare(context)` class method that registers its functions into the provided `EvaluationContext`.
149
+
150
+ | Module | Functions |
151
+ |---|---|
152
+ | `StdLibLet` | `let` |
153
+ | `StdLibControl` | `def`, `if`, `quote`, `block`, `eval` |
154
+ | `StdLibMath` | arithmetic and comparison operators |
155
+ | `StdLibString` | `concat`, `join`, `strip`, `lowercase`, `string-len`, `truncate`, `string-humanize`, `concat-list` |
156
+ | `StdLibList` | list construction and access |
157
+ | `StdLibAssoc` | associative list (key-value) operations |
158
+ | `StdLibEnum` | `map`, `filter`, `reduce`, and similar |
159
+ | `StdLibLogic` | `and`, `or`, `not` |
160
+ | `StdLibKind` | type predicates (`string?`, `number?`, etc.) |
161
+ | `StdLibExistence` | `nil?`, `present?` |
162
+ | `StdLibNumber` | number coercion/formatting |
163
+ | `StdLibJson` | JSON encode/decode |
164
+ | `StdLibRegexp` | regular expression matching |
165
+
166
+ **Key patterns**:
167
+ - Use `StdLib.new_context` to get a fresh context with all stdlib registered
168
+ - Add a new stdlib function by creating a `declare_<name>` private method and calling it from `declare`
169
+ - Guard declarations with `||=` so host apps can override individual functions before calling `StdLib.declare`
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in introhive_expression_language.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,87 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ introhive_expression_language (0.6.8)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activesupport (7.0.7.2)
10
+ concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ i18n (>= 1.6, < 2)
12
+ minitest (>= 5.1)
13
+ tzinfo (~> 2.0)
14
+ ast (2.4.1)
15
+ bigdecimal (4.1.0)
16
+ byebug (12.0.0)
17
+ coderay (1.1.3)
18
+ concurrent-ruby (1.3.5)
19
+ drb (2.2.3)
20
+ i18n (1.14.7)
21
+ concurrent-ruby (~> 1.0)
22
+ method_source (1.1.0)
23
+ minitest (5.25.5)
24
+ mocha (2.8.2)
25
+ ruby2_keywords (>= 0.0.5)
26
+ mutex_m (0.3.0)
27
+ parallel (1.20.0)
28
+ parser (2.7.2.0)
29
+ ast (~> 2.4.1)
30
+ pry (0.15.2)
31
+ coderay (~> 1.1)
32
+ method_source (~> 1.0)
33
+ pry-byebug (3.11.0)
34
+ byebug (~> 12.0)
35
+ pry (>= 0.13, < 0.16)
36
+ rack (3.1.21)
37
+ rainbow (3.0.0)
38
+ rake (13.0.1)
39
+ rexml (3.3.9)
40
+ rubocop (0.83.0)
41
+ parallel (~> 1.10)
42
+ parser (>= 2.7.0.1)
43
+ rainbow (>= 2.2.2, < 4.0)
44
+ rexml
45
+ ruby-progressbar (~> 1.7)
46
+ unicode-display_width (>= 1.4.0, < 2.0)
47
+ rubocop-performance (1.5.1)
48
+ rubocop (>= 0.71.0)
49
+ rubocop-rails (2.3.2)
50
+ rack (>= 1.1)
51
+ rubocop (>= 0.72.0)
52
+ ruby-progressbar (1.10.1)
53
+ ruby2_keywords (0.0.5)
54
+ shoulda (4.0.0)
55
+ shoulda-context (~> 2.0)
56
+ shoulda-matchers (~> 4.0)
57
+ shoulda-context (2.0.0)
58
+ shoulda-matchers (4.4.1)
59
+ activesupport (>= 4.2.0)
60
+ tzinfo (2.0.6)
61
+ concurrent-ruby (~> 1.0)
62
+ unicode-display_width (1.7.0)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ activesupport (~> 7.0.7.2)
69
+ bigdecimal (>= 4.1.0)
70
+ bundler (>= 2.2.10)
71
+ drb (>= 2.2.3)
72
+ introhive_expression_language!
73
+ minitest (~> 5.0)
74
+ mocha (~> 2.0)
75
+ mutex_m (>= 0.3.0)
76
+ pry (~> 0.14)
77
+ pry-byebug
78
+ rack (~> 3.1.21)
79
+ rake (~> 13.0.1)
80
+ rexml (~> 3.3.9)
81
+ rubocop (= 0.83.0)
82
+ rubocop-performance (= 1.5.1)
83
+ rubocop-rails (= 2.3.2)
84
+ shoulda
85
+
86
+ BUNDLED WITH
87
+ 4.0.12
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # IntrohiveExpressionLanguage
2
+
3
+ [![CI](https://github.com/Introhive/introhive_expression_language/actions/workflows/ci.yml/badge.svg)](https://github.com/Introhive/introhive_expression_language/actions/workflows/ci.yml)
4
+
5
+ IEL is a programming language built primarily for embedding into ruby software. It is designed to be a safe language for end users to use. It is in the functional style of languages like lisp which makes it very appropriate for expression evaluation. It also makes more complex logic easy to implement as users can define their own functions and call them. Its standard library contains functions to manipulate data and control execution flow.
6
+
7
+ https://docs.google.com/document/d/1m1lz-jr3tgKTLjGsPPIxEsCIWHXEsmP-iZ7ogNaegZY/edit#heading=h.bq98xgbgvoii
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'introhive_expression_language'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install introhive_expression_language
24
+
25
+ ## Development
26
+
27
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
28
+
29
+ To install this gem onto your local machine, run `bundle exec rake install`. See the [Versioning](#versioning) section for instructions on releasing a new version.
30
+
31
+ ## Versioning
32
+
33
+ Every change to this gem — including bug fixes, new features, and dependency updates — requires a version bump in `lib/introhive_expression_language/version.rb` before merging.
34
+
35
+ This project follows [Semantic Versioning](https://semver.org/):
36
+
37
+ | Version segment | When to increment |
38
+ |---|---|
39
+ | `x` (major) | Breaking changes to the public API (e.g. removing or renaming functions in `Evaluator`, `EvaluationContext`, or `StdLib`) |
40
+ | `y` (minor) | New backwards-compatible functionality (e.g. new stdlib functions, new evaluator features, new public Ruby API) |
41
+ | `z` (patch) | Backwards-compatible fixes, dependency updates, Ruby version bumps, tooling changes |
42
+
43
+ ### Steps to release
44
+
45
+ 1. Bump the version in `lib/introhive_expression_language/version.rb`
46
+ 2. Run `bundle install` to update `Gemfile.lock`
47
+ 3. Commit both files and merge the PR
48
+ 4. Run `bundle exec rake release` to tag, push, and publish the `.gem`
49
+
50
+ After the new version is published, update the `introhive_expression_language` reference in any downstream projects to point to the new version.
51
+
52
+ ## Continuous Integration
53
+
54
+ This project uses GitHub Actions for continuous integration. The CI workflow runs on every push and pull request to the `master` branch. You can view the status of builds and tests in the [Actions tab](https://github.com/Introhive/introhive_expression_language/actions).
55
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "introhive_expression_language"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,54 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "introhive_expression_language/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "introhive_expression_language"
8
+ spec.version = IntrohiveExpressionLanguage::VERSION
9
+ spec.authors = ["Jacob O'Reilly"]
10
+ spec.email = ["jacob.oreilly@introhive.com"]
11
+
12
+ spec.summary = %q{A programming language built primarily for embedding into ruby software.}
13
+ spec.description = %q{IEL is a programming language built primarily for embedding into ruby software. It is designed to be a safe language for end users to use. It is in the functional style of languages like lisp which makes it very appropriate for expression evaluation. It also makes more complex logic easy to implement as users can define their own functions and call them. Its standard library contains functions to manipulate data and control execution flow.}
14
+ # spec.homepage = "Put your gem's website or public repo URL here."
15
+
16
+ # # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ # if spec.respond_to?(:metadata)
19
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
+
21
+ # spec.metadata["homepage_uri"] = spec.homepage
22
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
23
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
24
+ # else
25
+ # raise "RubyGems 2.0 or newer is required to protect against " \
26
+ # "public gem pushes."
27
+ # end
28
+
29
+ # Specify which files should be added to the gem when it is released.
30
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
32
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ end
34
+ spec.bindir = "exe"
35
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ["lib"]
37
+
38
+ spec.add_development_dependency "activesupport", "~> 7.0.7.2"
39
+ spec.add_development_dependency "bigdecimal", ">= 4.1.0"
40
+ spec.add_development_dependency "mutex_m", ">= 0.3.0"
41
+ spec.add_development_dependency "drb", ">= 2.2.3"
42
+ spec.add_development_dependency 'bundler', '>= 2.2.10'
43
+ spec.add_development_dependency "minitest", "~> 5.0"
44
+ spec.add_development_dependency "mocha", "~> 2.0"
45
+ spec.add_development_dependency "pry", "~> 0.14"
46
+ spec.add_development_dependency "pry-byebug"
47
+ spec.add_development_dependency "rack", "~> 3.1.21"
48
+ spec.add_development_dependency "rake", "~> 13.0.1"
49
+ spec.add_development_dependency "rexml", "~> 3.3.9"
50
+ spec.add_development_dependency 'rubocop', '= 0.83.0'
51
+ spec.add_development_dependency 'rubocop-performance', '= 1.5.1'
52
+ spec.add_development_dependency 'rubocop-rails', '= 2.3.2'
53
+ spec.add_development_dependency "shoulda"
54
+ end
@@ -0,0 +1,35 @@
1
+ module Platform
2
+ module IEL
3
+ class EvaluationContext
4
+ attr_reader :enclosing_context
5
+
6
+ def initialize(enclosing_context = nil)
7
+ @enclosing_context = enclosing_context
8
+ @symbols = {}
9
+ end
10
+
11
+ def [](symbol)
12
+ out = @symbols[symbol]
13
+ return out if out.present?
14
+ return @enclosing_context[symbol] if @enclosing_context
15
+ nil
16
+ end
17
+
18
+ def []=(symbol, symbol_detail)
19
+ raise StandardError, "Cannot write symbol '#{symbol}' value '#{symbol_detail.inspect}' as it is not of type Platform::IEL::SexpParser::Node" unless symbol_detail.is_a?(SexpParser::Node)
20
+ raise StandardError, "Cannot redefine constant symbol '#{symbol}' value '#{symbol_detail.inspect}'" if constant_name?(symbol) && self[symbol]
21
+ @symbols[symbol] = symbol_detail
22
+ end
23
+
24
+ def constant_name?(symbol)
25
+ symbol.start_with?('C_')
26
+ end
27
+
28
+ # Find and return the root context by following enclosing contexts.
29
+ def root_context
30
+ return enclosing_context.root_context if enclosing_context
31
+ self
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ module Platform
2
+ module IEL
3
+ class EvaluationError < StandardError
4
+ def initialize(message, node = Platform::IEL::SexpParser::Node.nil)
5
+ super "#{message}#{node.try(:source_desc)}"
6
+ end
7
+ end
8
+ end
9
+ end