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.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +80 -0
- data/.github/pull_request_template.md +17 -0
- data/.github/workflows/ci.yml +31 -0
- data/.gitignore +15 -0
- data/.qlty/qlty.toml +10 -0
- data/.ruby-version +1 -0
- data/CLAUDE.md +169 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +87 -0
- data/README.md +55 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/introhive_expression_language.gemspec +54 -0
- data/lib/introhive_expression_language/iel/evaluation_context.rb +35 -0
- data/lib/introhive_expression_language/iel/evaluation_error.rb +9 -0
- data/lib/introhive_expression_language/iel/evaluator.rb +166 -0
- data/lib/introhive_expression_language/iel/node_util.rb +65 -0
- data/lib/introhive_expression_language/iel/parser.rb +30 -0
- data/lib/introhive_expression_language/iel/sexp_parser.rb +339 -0
- data/lib/introhive_expression_language/iel/std_lib.rb +43 -0
- data/lib/introhive_expression_language/iel/std_lib_assoc.rb +84 -0
- data/lib/introhive_expression_language/iel/std_lib_control.rb +81 -0
- data/lib/introhive_expression_language/iel/std_lib_enum.rb +30 -0
- data/lib/introhive_expression_language/iel/std_lib_existence.rb +19 -0
- data/lib/introhive_expression_language/iel/std_lib_json.rb +38 -0
- data/lib/introhive_expression_language/iel/std_lib_kind.rb +88 -0
- data/lib/introhive_expression_language/iel/std_lib_let.rb +22 -0
- data/lib/introhive_expression_language/iel/std_lib_list.rb +85 -0
- data/lib/introhive_expression_language/iel/std_lib_logic.rb +52 -0
- data/lib/introhive_expression_language/iel/std_lib_math.rb +75 -0
- data/lib/introhive_expression_language/iel/std_lib_number.rb +28 -0
- data/lib/introhive_expression_language/iel/std_lib_regexp.rb +30 -0
- data/lib/introhive_expression_language/iel/std_lib_string.rb +79 -0
- data/lib/introhive_expression_language/iel/symbol_detail.rb +16 -0
- data/lib/introhive_expression_language/iel.rb +2 -0
- data/lib/introhive_expression_language/version.rb +3 -0
- data/lib/introhive_expression_language.rb +9 -0
- 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
data/.qlty/qlty.toml
ADDED
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
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
|
+
[](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
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,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
|