Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Gemfile.lock
*.ler
*.pax
TODO.*.md
TODO.refactor/
debug_*.rb
measure_mem.rb
tmp_*.rb
Expand All @@ -40,3 +41,4 @@ Gemfile.local
Gemfile.local.lock
Gemfile.original
benchmark/
CLAUDE.md
79 changes: 17 additions & 62 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,56 +1,18 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2026-05-14 10:03:28 UTC using RuboCop version 1.86.0.
# on 2026-06-05 10:03:10 UTC using RuboCop version 1.86.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 7
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyleAlignWith.
# SupportedStylesAlignWith: either, start_of_block, start_of_line
Layout/BlockAlignment:
Exclude:
- 'lib/expressir/express/builder_registry.rb'
- 'spec/expressir/express/formatter_roundtrip_spec.rb'

# Offense count: 5
# This cop supports safe autocorrection (--autocorrect).
Layout/BlockEndNewline:
Exclude:
- 'lib/expressir/express/builder_registry.rb'
- 'spec/expressir/express/formatter_roundtrip_spec.rb'

# Offense count: 8
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
# SupportedStylesAlignWith: start_of_line, relative_to_receiver
Layout/IndentationWidth:
Exclude:
- 'lib/expressir/express/builder_registry.rb'
- 'spec/expressir/express/formatter_roundtrip_spec.rb'

# Offense count: 1068
# Offense count: 1072
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
# URISchemes: http, https
Layout/LineLength:
Enabled: false

# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
Layout/MultilineBlockLayout:
Exclude:
- 'spec/expressir/express/formatter_roundtrip_spec.rb'

# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowInHeredoc.
Layout/TrailingWhitespace:
Exclude:
- 'spec/expressir/express/formatter_roundtrip_spec.rb'

# Offense count: 9
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
Lint/DuplicateBranch:
Expand All @@ -62,11 +24,10 @@ Lint/DuplicateBranch:
- 'lib/expressir/express/remark_attacher.rb'
- 'lib/expressir/model/search_engine.rb'

# Offense count: 2
# Offense count: 1
Lint/DuplicateCaseCondition:
Exclude:
- 'lib/expressir/commands/package.rb'
- 'lib/expressir/express/formatter.rb'

# Offense count: 1
Lint/DuplicateMethods:
Expand All @@ -89,7 +50,12 @@ Lint/UnusedMethodArgument:
- 'lib/expressir/express/cache.rb'
- 'lib/expressir/express/parser.rb'

# Offense count: 239
# Offense count: 2
Lint/UselessConstantScoping:
Exclude:
- 'lib/expressir/express/remark_attacher.rb'

# Offense count: 240
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
Metrics/AbcSize:
Enabled: false
Expand All @@ -105,12 +71,12 @@ Metrics/BlockLength:
Metrics/BlockNesting:
Max: 6

# Offense count: 193
# Offense count: 190
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
Metrics/CyclomaticComplexity:
Enabled: false

# Offense count: 289
# Offense count: 290
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Max: 167
Expand All @@ -120,7 +86,7 @@ Metrics/MethodLength:
Metrics/ParameterLists:
Max: 8

# Offense count: 167
# Offense count: 162
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
Metrics/PerceivedComplexity:
Enabled: false
Expand Down Expand Up @@ -189,7 +155,7 @@ RSpec/ContextWording:
- 'spec/expressir/commands/validate_ascii_spec.rb'
- 'spec/expressir/model/repository_spec.rb'

# Offense count: 1
# Offense count: 2
# Configuration parameters: IgnoredMetadata.
RSpec/DescribeClass:
Exclude:
Expand All @@ -198,6 +164,7 @@ RSpec/DescribeClass:
- '**/spec/routing/**/*'
- '**/spec/system/**/*'
- '**/spec/views/**/*'
- 'spec/expressir/express/formatter_architecture_spec.rb'
- 'spec/expressir/integration/package_roundtrip_spec.rb'

# Offense count: 6
Expand All @@ -210,7 +177,7 @@ RSpec/DescribeMethod:
- 'spec/expressir/model/repository_statistics_spec.rb'
- 'spec/expressir/model/search_engine_advanced_spec.rb'

# Offense count: 460
# Offense count: 480
# Configuration parameters: CountAsOne.
RSpec/ExampleLength:
Max: 122
Expand Down Expand Up @@ -251,7 +218,7 @@ RSpec/IteratedExpectation:
RSpec/MessageSpies:
EnforcedStyle: receive

# Offense count: 588
# Offense count: 596
RSpec/MultipleExpectations:
Max: 114

Expand Down Expand Up @@ -291,23 +258,11 @@ RSpec/SpecFilePathFormat:
- 'spec/expressir/model/repository_statistics_spec.rb'
- 'spec/expressir/model/search_engine_advanced_spec.rb'

# Offense count: 4
# Offense count: 2
Security/MarshalLoad:
Exclude:
- 'lib/expressir/package/reader.rb'

# Offense count: 5
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
# FunctionalMethods: let, let!, subject, watch
# AllowedMethods: lambda, proc, it
Style/BlockDelimiters:
Exclude:
- 'lib/expressir/express/builder_registry.rb'
- 'spec/expressir/express/formatter_roundtrip_spec.rb'

# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, AllowComments.
Expand Down
159 changes: 159 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Breaking Changes

#### Repository Structure Change

The `Repository` class now uses a `files` attribute containing `ExpFile` objects instead of a direct `schemas` attribute.

**Old structure:**
```ruby
repository = Expressir::Model::Repository.new
repository.schemas << schema1
repository.schemas << schema2
```

**New structure:**
```ruby
repository = Expressir::Model::Repository.new
repository.add_schema(schema1)
repository.add_schema(schema2)

# Or with files:
exp_file = Expressir::Express::Parser.from_file("schema.exp")
repository.files << exp_file
```

#### ExpFile Model Introduced

A new `ExpFile` class represents a single EXPRESS file with its own preamble remarks and schemas:

```ruby
# ExpFile has:
# - path: the file path
# - schemas: array of schemas in the file
# - untagged_remarks: file-level preamble remarks

exp_file = Expressir::Model::ExpFile.new(path: "my_schema.exp")
exp_file.schemas = [schema]
exp_file.untagged_remarks = [remark_info]
```

#### Parser Return Type Changed

`Expressir::Express::Parser.from_file` now returns an `ExpFile` instead of a `Repository`:

```ruby
# Old: returned Repository
# New: returns ExpFile
exp_file = Expressir::Express::Parser.from_file("schema.exp")
exp_file.path # => "schema.exp"
exp_file.schemas # => [#<Expressir::Model::Declarations::Schema...>]
```

#### Error Class Changes

- `InvalidSchemaManifestError` → Use `ManifestValidationError` instead
- `Expressir::Express::CacheVersionMismatchError` → Use `Expressir::Express::Error::CacheVersionMismatchError`

#### RemarkInfo Required

Remark formatters now require `RemarkInfo` objects instead of strings:

```ruby
# Old:
formatter.format_preamble_remark("This is a remark")

# New:
remark = Expressir::Model::RemarkInfo.new(text: "This is a remark")
formatter.format_preamble_remark(remark)
```

### Added

- `Expressir::Model::ExpFile` class for representing EXPRESS files
- `Expressir::Model::Concerns` module with marker modules for O(1) type checking:
- `HasRemarkItems` - types that can have remark_items children
- `ScopeContainer` - types that can contain declarations
- `HasInformalPropositions` - types supporting informal propositions
- `HasWhereRules` - types supporting where rules
- `Repository#add_schema(schema)` method for adding schemas
- `Repository#files` attribute for storing ExpFile objects
- `Package::Builder#normalize_repository` ensures proper serialization format

### Changed

- `Repository#schemas` now returns schemas from both `files` and internal storage
- `Parser.from_file` returns `ExpFile` instead of `Repository`
- `Parser.from_files` creates `Repository` with `ExpFile` objects
- `Parser.from_exp` returns `ExpFile` instead of `Repository`
- `format_repository` in formatters handles both file-based and direct schemas
- Preamble remarks now attach to `ExpFile` instead of first `Schema`

### Removed

- All backward compatibility code for legacy serialized data
- `Repository#schemas=` writer (use `add_schema` instead)
- Legacy string handling in remark formatters
- `InvalidSchemaManifestError` alias (use `ManifestValidationError`)
- Legacy `@schemas` attribute migration in Repository
- Array-based type checking in `remark_attacher.rb` (replaced with module markers)

### Migration Guide

#### Updating Code That Uses Repository

```ruby
# Before:
repo = Expressir::Model::Repository.new
repo.schemas << schema

# After:
repo = Expressir::Model::Repository.new
repo.add_schema(schema)
```

#### Updating Code That Parses Files

```ruby
# Before:
repo = Expressir::Express::Parser.from_file("schema.exp")
schema = repo.schemas.first

# After:
exp_file = Expressir::Express::Parser.from_file("schema.exp")
schema = exp_file.schemas.first

# Or wrap in repository:
repo = Expressir::Model::Repository.new
repo.files << Expressir::Express::Parser.from_file("schema.exp")
```

#### Updating Serialized Packages

Old `.ler` packages need to be regenerated with the new format:

```ruby
# Load old package (will fail with new code)
# repo = Expressir::Model::Repository.from_package("old.ler")

# Regenerate by parsing original EXPRESS files
exp_file = Expressir::Express::Parser.from_file("schema.exp")
repo = Expressir::Model::Repository.new
repo.files << exp_file
repo.export_to_package("new.ler", name: "My Package", version: "1.0.0")
```

## [2.2.1] - 2024-03-14

### Changed

- Refactored `require` to `autoload` pattern for better load performance
- Updated error handling to use error classes instead of `abort`
Loading
Loading