abstract-synthesizer 0.0.12 → 0.0.13

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.
data/GEMINI.md ADDED
@@ -0,0 +1,13 @@
1
+ # Project Root Directory
2
+
3
+ This directory contains the core files for the `abstract-synthesizer` Ruby gem.
4
+
5
+ - `README.md`: Provides a general overview of the project.
6
+ - `abstract-synthesizer.gemspec`: Defines the gem's metadata, dependencies, and files to be included in the gem. It specifies the gem's name, version, authors, description, and development dependencies.
7
+ - `Rakefile`: Contains Rake tasks for common development operations such as running tests (`rspec`) and linting (`rubocop`).
8
+ - `Gemfile`, `Gemfile.lock`, `gemset.nix`, `flake.nix`, `flake.lock`: These files are related to dependency management using Bundler and Nix. `gemset.nix` is generated by `bundix` for Nix integration.
9
+ - `.rubocop.yml`: Configuration file for RuboCop, a Ruby static code analyzer.
10
+ - `.gitignore`: Specifies files and directories to be ignored by Git.
11
+ - `LICENSE`: Contains the licensing information for the project (MIT License).
12
+
13
+ The primary purpose of this gem is to "create resource based configuration DSL".
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abstract-synthesizer (0.0.12)
4
+ abstract-synthesizer (0.0.13)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -24,7 +24,7 @@ GEM
24
24
  rspec-core (~> 3.13.0)
25
25
  rspec-expectations (~> 3.13.0)
26
26
  rspec-mocks (~> 3.13.0)
27
- rspec-core (3.13.4)
27
+ rspec-core (3.13.5)
28
28
  rspec-support (~> 3.13.0)
29
29
  rspec-expectations (3.13.5)
30
30
  diff-lcs (>= 1.2.0, < 2.0)
@@ -33,7 +33,7 @@ GEM
33
33
  diff-lcs (>= 1.2.0, < 2.0)
34
34
  rspec-support (~> 3.13.0)
35
35
  rspec-support (3.13.4)
36
- rubocop (1.76.1)
36
+ rubocop (1.77.0)
37
37
  json (~> 2.3)
38
38
  language_server-protocol (~> 3.17.0.2)
39
39
  lint_roller (~> 1.1.0)
@@ -41,7 +41,7 @@ GEM
41
41
  parser (>= 3.3.0.2)
42
42
  rainbow (>= 2.2.2, < 4.0)
43
43
  regexp_parser (>= 2.9.3, < 3.0)
44
- rubocop-ast (>= 1.45.0, < 2.0)
44
+ rubocop-ast (>= 1.45.1, < 2.0)
45
45
  ruby-progressbar (~> 1.7)
46
46
  unicode-display_width (>= 2.4.0, < 4.0)
47
47
  rubocop-ast (1.45.1)
data/docs/overview.md ADDED
@@ -0,0 +1,36 @@
1
+ # Abstract Synthesizer Overview
2
+
3
+ The `abstract-synthesizer` gem provides a Ruby DSL (Domain Specific Language) for defining hierarchical, resource-based configurations. It allows users to create structured data (manifests) using a declarative syntax, similar to how configuration files are often written.
4
+
5
+ ## Core Concepts
6
+
7
+ - **Synthesizer**: The main component responsible for processing the DSL and building the manifest. It dynamically handles method calls to interpret resource definitions and field assignments.
8
+ - **Manifest**: The resulting hierarchical data structure (a Ruby Hash) generated by the synthesizer, representing the defined configuration.
9
+ - **Keys**: A predefined set of allowed methods that the synthesizer recognizes as valid resource or field names within the DSL.
10
+ - **Bury**: A utility module that extends the `Hash` class, enabling nested assignment of values, which is fundamental for building the hierarchical manifest.
11
+
12
+ ## Architecture Diagram
13
+
14
+ ```mermaid
15
+ graph TD
16
+ A[User DSL Input] --> B{AbstractSynthesizer};
17
+ B -- "method_missing calls" --> C[abstract_method_missing];
18
+ C -- "Validates method/args" --> D{Validation Logic};
19
+ D -- "Raises Errors" --> E[Custom Errors];
20
+ C -- "Builds nested hash" --> F[Bury Module (extends Hash)];
21
+ F --> G[Manifest (Ruby Hash)];
22
+ B -- "Returns" --> G;
23
+
24
+ subgraph SynthesizerFactory
25
+ H[create_synthesizer] --> B;
26
+ end
27
+ ```
28
+
29
+ ## How it Works
30
+
31
+ 1. **Initialization**: A `Synthesizer` instance is created, optionally via the `SynthesizerFactory`, which injects the allowed `keys` for the DSL.
32
+ 2. **DSL Evaluation**: The `synthesize` method evaluates a Ruby block or string. Inside this context, method calls are intercepted.
33
+ 3. **Dynamic Method Handling**: The `method_missing` method (overridden in `AbstractSynthesizer` or dynamically defined by `SynthesizerFactory`) delegates to `abstract_method_missing`.
34
+ 4. **Validation**: `abstract_method_missing` validates the called method against the allowed `keys` and checks argument counts.
35
+ 5. **Manifest Building**: Based on the method and arguments, the synthesizer uses the `bury` method (provided by the `Bury` module) to insert data into the `translation[:manifest]` hash, creating nested structures as needed.
36
+ 6. **Result**: The final `manifest` hash represents the structured configuration defined by the DSL.
data/docs/usage.md ADDED
@@ -0,0 +1,116 @@
1
+ # Usage Guide
2
+
3
+ This guide explains how to use the `abstract-synthesizer` gem to define resource-based configurations.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'abstract-synthesizer'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ gem install abstract-synthesizer
23
+ ```
24
+
25
+ ## Basic Usage
26
+
27
+ To use the synthesizer, you typically create an instance using the `SynthesizerFactory` and then define your configuration within a `synthesize` block.
28
+
29
+ ```ruby
30
+ require 'abstract-synthesizer'
31
+
32
+ # Define the allowed keys for your DSL
33
+ # These keys will be the valid methods you can call in your DSL block
34
+ resource_keys = %i[server database user]
35
+
36
+ synthesizer = SynthesizerFactory.create_synthesizer(name: :my_config, keys: resource_keys)
37
+
38
+ synthesizer.synthesize do
39
+ server :web_server, :production do
40
+ host 'example.com'
41
+ port 8080
42
+ ssl true
43
+ end
44
+
45
+ server :api_server, :development do
46
+ host 'localhost'
47
+ port 3000
48
+ end
49
+
50
+ database :main_db, :mysql do
51
+ username 'admin'
52
+ password 'secret'
53
+ host 'db.example.com'
54
+ end
55
+
56
+ user :admin_user do
57
+ name 'Administrator'
58
+ email 'admin@example.com'
59
+ end
60
+ end
61
+
62
+ # Access the generated manifest
63
+ puts synthesizer.synthesis.inspect
64
+ # Expected Output (simplified):
65
+ # {
66
+ # :server => {
67
+ # :web_server => {
68
+ # :production => {
69
+ # :host => "example.com", :port => 8080, :ssl => true
70
+ # }
71
+ # },
72
+ # :api_server => {
73
+ # :development => {
74
+ # :host => "localhost", :port => 3000
75
+ # }
76
+ # }
77
+ # },
78
+ # :database => {
79
+ # :main_db => {
80
+ # :mysql => {
81
+ # :username => "admin", :password => "secret", :host => "db.example.com"
82
+ # }
83
+ # }
84
+ # },
85
+ # :user => {
86
+ # :admin_user => {
87
+ # :name => "Administrator", :email => "admin@example.com"
88
+ # }
89
+ # }
90
+ # }
91
+ ```
92
+
93
+ ## DSL Structure
94
+
95
+ The DSL follows a hierarchical structure:
96
+
97
+ - **Resource Definition**: The top-level methods in your `synthesize` block correspond to the `keys` you provided to `create_synthesizer`. These methods can take multiple arguments, which become nested keys in the manifest.
98
+ ```ruby
99
+ resource_key :first_level_identifier, :second_level_identifier do
100
+ # ... fields or nested resources
101
+ end
102
+ ```
103
+
104
+ - **Field Assignment**: Inside a resource block, methods without a block are treated as field assignments. They take a single argument, which is the value for that field.
105
+ ```ruby
106
+ field_name 'field_value'
107
+ another_field 123
108
+ ```
109
+
110
+ ## Error Handling
111
+
112
+ The gem provides specific error classes for common issues:
113
+
114
+ - `InvalidSynthesizerKeyError`: Raised when you try to use a method in your DSL that was not included in the `keys` provided to `SynthesizerFactory.create_synthesizer`.
115
+ - `TooManyFieldValuesError`: Raised when a field assignment method receives more than one argument.
116
+ - `NotEnoughResourceKeys`: Raised when a resource definition does not receive the expected number of arguments (e.g., if a top-level resource expects two identifiers but only one is provided).
data/flake.lock CHANGED
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "nixpkgs": {
22
22
  "locked": {
23
- "lastModified": 1739319052,
24
- "narHash": "sha256-L8Tq1dnW96U70vrNpCCGCLHz4rX1GhNRCrRI/iox9wc=",
23
+ "lastModified": 1751031243,
24
+ "narHash": "sha256-LE6HorMxlsjj0sJ5MzV0UMAQzzG2R438rVFjSM9/LCU=",
25
25
  "owner": "NixOS",
26
26
  "repo": "nixpkgs",
27
- "rev": "83a2581c81ff5b06f7c1a4e7cc736a455dfcf7b4",
27
+ "rev": "618b6ce64508a2c821111fffc3f4153c6675acef",
28
28
  "type": "github"
29
29
  },
30
30
  "original": {
@@ -59,11 +59,11 @@
59
59
  "nixpkgs": "nixpkgs_2"
60
60
  },
61
61
  "locked": {
62
- "lastModified": 1725677741,
63
- "narHash": "sha256-CySXGzqycagfrWdcTwzM3Zo1MMm9uUtePYER9BvrW8s=",
62
+ "lastModified": 1744623277,
63
+ "narHash": "sha256-0HWA2YD9v71SHyMF11PKnVJcHnrHhRLHDCldlUbzYII=",
64
64
  "owner": "inscapist",
65
65
  "repo": "ruby-nix",
66
- "rev": "1f3756f8a713171bf891b39c0d3b1fe6d83a4a63",
66
+ "rev": "43964ced23803f49e2d307fbbfd4e03ed23760c0",
67
67
  "type": "github"
68
68
  },
69
69
  "original": {
data/gemset.nix CHANGED
@@ -6,7 +6,7 @@
6
6
  path = ./.;
7
7
  type = "path";
8
8
  };
9
- version = "0.0.12";
9
+ version = "0.0.13";
10
10
  };
11
11
  ast = {
12
12
  groups = ["default" "development"];
@@ -146,10 +146,10 @@
146
146
  platforms = [];
147
147
  source = {
148
148
  remotes = ["https://rubygems.org"];
149
- sha256 = "0n1rlagplpcgp41s3r68z01539aivwj0cn3v19hq4p3pgdmibnpr";
149
+ sha256 = "18sgga9zjrd5579m9rpb78l7yn9a0bjzwz51z5kiq4y6jwl6hgxb";
150
150
  type = "gem";
151
151
  };
152
- version = "3.13.4";
152
+ version = "3.13.5";
153
153
  };
154
154
  rspec-expectations = {
155
155
  dependencies = ["diff-lcs" "rspec-support"];
@@ -189,10 +189,10 @@
189
189
  platforms = [];
190
190
  source = {
191
191
  remotes = ["https://rubygems.org"];
192
- sha256 = "1rz0wwhxy6rv0kk2m8jp77fbhwgs7m01p2yys9bj3kwl0xsjsnp1";
192
+ sha256 = "1h48rhmp178ppzc4ybfj42a2savs4bxgy3bvw95i4ypgfm2hndhz";
193
193
  type = "gem";
194
194
  };
195
- version = "1.76.1";
195
+ version = "1.77.0";
196
196
  };
197
197
  rubocop-ast = {
198
198
  dependencies = ["parser" "prism"];
data/lib/GEMINI.md ADDED
@@ -0,0 +1,26 @@
1
+ # lib/ Directory
2
+
3
+ This directory contains the main source code for the `abstract-synthesizer` gem.
4
+
5
+ - `abstract-synthesizer.rb`: This is the primary entry point for the gem. It defines the `AbstractSynthesizer` class and the `SynthesizerFactory` module.
6
+
7
+ ## AbstractSynthesizer Class
8
+
9
+ The `AbstractSynthesizer` class is designed to create a resource-based configuration DSL (Domain Specific Language). It allows users to define hierarchical data structures (manifests) using a Ruby-like syntax.
10
+
11
+ Key features and methods:
12
+ - `initialize`: Initializes the synthesizer with a `translation` hash, which stores the `ancestors` (current path in the manifest), `manifest` (the generated data structure), and `context`.
13
+ - `clear!`: Resets the `manifest`.
14
+ - `synthesis`: Returns the generated `manifest`.
15
+ - `synthesize(content = nil, &block)`: Evaluates the provided content or block to build the manifest. This is where the DSL is processed.
16
+ - `manifest`: An alias for `synthesis`.
17
+ - `valid_method?(method, keys)`: Internal method to check if a method call is valid within the current context (resource definition or field assignment).
18
+ - `validate_method(method, keys)`: Raises `InvalidSynthesizerKeyError` if a method is not valid.
19
+ - `validate_args(args)`: Validates the number of arguments based on the current context, raising `NotEnoughResourceKeys` or `TooManyFieldValuesError`.
20
+ - `abstract_method_missing(method, keys, *args)`: This is the core of the DSL. It dynamically handles method calls, interpreting them as resource keys or field assignments, and building the `translation[:manifest]` accordingly. It uses the `Bury` module for nested data insertion.
21
+
22
+ ## SynthesizerFactory Module
23
+
24
+ This module provides a factory method to create instances of `AbstractSynthesizer`.
25
+
26
+ - `create_synthesizer(name:, keys:)`: Creates a new `AbstractSynthesizer` instance and dynamically defines its `method_missing` method. This `method_missing` delegates to `abstract_method_missing` within the `AbstractSynthesizer` instance, passing the allowed `keys` for the DSL. This allows for flexible definition of the DSL structure based on the provided `keys`.
@@ -0,0 +1,5 @@
1
+ # lib/abstract-synthesizer/ Directory
2
+
3
+ This directory contains modules and core components that support the `AbstractSynthesizer`.
4
+
5
+ - `version.rb`: Defines the version number of the `abstract-synthesizer` gem within the `Meta` module. This file is used by the `gemspec` to set the gem's version.
@@ -0,0 +1,7 @@
1
+ # lib/abstract-synthesizer/errors/ Directory
2
+
3
+ This directory contains custom error classes used by the `abstract-synthesizer` gem. These errors are raised when specific conditions are not met during the synthesis process, providing clear feedback to the user.
4
+
5
+ - `invalid_synthesizer_key_error.rb`: Defines `InvalidSynthesizerKeyError`. This error is raised when the synthesizer attempts to process a key (method call) that is not defined or recognized as a valid resource key within the DSL.
6
+ - `not_enough_resource_keys.rb`: Defines `NotEnoughResourceKeys`. This error is raised when an insufficient number of resource keys are provided, typically during the initial definition of a resource.
7
+ - `too_many_field_values.rb`: Defines `TooManyFieldValuesError`. This error is raised when too many field values are provided for a given field, indicating an incorrect usage of the DSL.
@@ -0,0 +1,5 @@
1
+ # lib/abstract-synthesizer/primitives/ Directory
2
+
3
+ This directory contains primitive modules or classes that provide fundamental functionalities used by the `abstract-synthesizer`.
4
+
5
+ - `bury.rb`: Defines the `Bury` module. This module extends the `Hash` class with a `bury` method. The `bury` method allows for nested assignment of values within a hash, creating intermediate hashes as needed. This is crucial for building the hierarchical `manifest` within the `AbstractSynthesizer`.
@@ -1,3 +1,3 @@
1
1
  module Meta
2
- VERSION = %(0.0.12).freeze
2
+ VERSION = %(0.0.13).freeze
3
3
  end
@@ -78,7 +78,7 @@ class AbstractSynthesizer
78
78
  method = method.to_sym
79
79
 
80
80
  validate_method(method, keys)
81
- # validate_args(args)
81
+ validate_args(args)
82
82
 
83
83
  keys.each do |key|
84
84
  if key.eql?(translation[:context])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abstract-synthesizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - drzzln@protonmail.com
@@ -60,20 +60,28 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - ".gitignore"
63
+ - ".nix_shell_env.sh"
63
64
  - ".rubocop.yml"
65
+ - GEMINI.md
64
66
  - Gemfile
65
67
  - Gemfile.lock
66
68
  - LICENSE
67
69
  - README.md
68
70
  - Rakefile
69
71
  - abstract-synthesizer.gemspec
72
+ - docs/overview.md
73
+ - docs/usage.md
70
74
  - flake.lock
71
75
  - flake.nix
72
76
  - gemset.nix
77
+ - lib/GEMINI.md
73
78
  - lib/abstract-synthesizer.rb
79
+ - lib/abstract-synthesizer/GEMINI.md
80
+ - lib/abstract-synthesizer/errors/GEMINI.md
74
81
  - lib/abstract-synthesizer/errors/invalid_synthesizer_key_error.rb
75
82
  - lib/abstract-synthesizer/errors/not_enough_resource_keys.rb
76
83
  - lib/abstract-synthesizer/errors/too_many_field_values.rb
84
+ - lib/abstract-synthesizer/primitives/GEMINI.md
77
85
  - lib/abstract-synthesizer/primitives/bury.rb
78
86
  - lib/abstract-synthesizer/version.rb
79
87
  homepage: https://github.com/drzln/abstract-synthesizer