oselvar-var 0.3.2
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/lib/oselvar/var/dsl.rb +36 -0
- data/lib/oselvar/var/internal.rb +118 -0
- data/lib/oselvar/var/registry.rb +30 -0
- data/lib/oselvar/var.rb +13 -0
- metadata +76 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: bb0852755c7a3a3b12c48ba5a068b697d0ae7e56e9fab0119adb7edfe1f4ff87
|
|
4
|
+
data.tar.gz: 308eb73b130b267ecc468f32ca0cd22e02b443c5a27170616749f0f822007d3a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cd02c874113a84d2ff1b53239ec567dd463c429a34f6f13de5bce235706c3f645140c6741d11461a4e9746ab325134de5dd1cc78be9bb73549855553ca27f03c
|
|
7
|
+
data.tar.gz: 9a394baac86793e5efa3b3926b9d80766cb7e6003e0436ebe430094ed31cf2be76c5ce1b87fdcbc7126b5ca5213bc27de81a56e589434fe8f7e03ae50aeeeef9
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'oselvar/var/internal'
|
|
4
|
+
|
|
5
|
+
# `steps` as a top-level method, available in any step file after
|
|
6
|
+
# `require "oselvar/var"` (idiomatic for BDD step DSLs, like Cucumber-Ruby's
|
|
7
|
+
# Given/When/Then). It takes a block in which bare `stimulus`, `sensor` and
|
|
8
|
+
# `param` register the file's steps:
|
|
9
|
+
#
|
|
10
|
+
# steps(greeting: '') do
|
|
11
|
+
# stimulus('I greet {string}') { |_state, name| { greeting: "Hello, #{name}!" } }
|
|
12
|
+
# sensor('the greeting is {string}') { |state, _expected| state[:greeting] }
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# The initial state is optional and may be given as keyword arguments, a Hash,
|
|
16
|
+
# or a Proc factory (called fresh per example); omit it entirely for stateless
|
|
17
|
+
# step files. The state is keyed by the calling file so contexts never bleed
|
|
18
|
+
# across step files.
|
|
19
|
+
module Kernel
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def steps(state = nil, **kwstate, &block)
|
|
23
|
+
initial =
|
|
24
|
+
if state.is_a?(Proc)
|
|
25
|
+
state
|
|
26
|
+
elsif !kwstate.empty?
|
|
27
|
+
kwstate
|
|
28
|
+
else
|
|
29
|
+
state || {}
|
|
30
|
+
end
|
|
31
|
+
factory = initial.is_a?(Proc) ? initial : -> { initial }
|
|
32
|
+
builder = Oselvar::Var::Internal.register(factory, caller_locations(1, 1).first.path)
|
|
33
|
+
builder.instance_eval(&block) if block
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'oselvar/var/core'
|
|
4
|
+
|
|
5
|
+
module Oselvar
|
|
6
|
+
module Var
|
|
7
|
+
# The module-scope step-registration accumulator behind the block DSL
|
|
8
|
+
# `steps(...) do stimulus(...); sensor(...) end`. Mirrors @oselvar/var's
|
|
9
|
+
# internal.ts. A step file, when loaded, calls steps() once; the Builder its
|
|
10
|
+
# block registers into these accumulators. The runner/harness then reads
|
|
11
|
+
# them via build_registry / context_factory.
|
|
12
|
+
module Internal
|
|
13
|
+
@steps = []
|
|
14
|
+
@context_factories_by_file = {}
|
|
15
|
+
@custom_types = []
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# Register a file's state factory and return a Builder whose
|
|
19
|
+
# stimulus/sensor/param methods accumulate that file's steps. +factory+
|
|
20
|
+
# is a callable (or nil for empty state); +source_file+ keys the
|
|
21
|
+
# per-file context factory. Raises if called twice for one file.
|
|
22
|
+
def register(factory, source_file)
|
|
23
|
+
raise "steps() called more than once in #{source_file}" if @context_factories_by_file.key?(source_file)
|
|
24
|
+
|
|
25
|
+
@context_factories_by_file[source_file] = factory || -> { {} }
|
|
26
|
+
Builder.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Accumulate one step. The handler's source_location anchors it to the
|
|
30
|
+
# line the block is written on.
|
|
31
|
+
def add_step(expression, handler, kind)
|
|
32
|
+
file, line = handler.source_location
|
|
33
|
+
@steps << {
|
|
34
|
+
expression: expression, source_file: file, source_line: line,
|
|
35
|
+
handler: handler, kind: kind
|
|
36
|
+
}
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Accumulate one custom parameter type.
|
|
41
|
+
def add_custom_type(name, regexp, parse, format)
|
|
42
|
+
@custom_types << { name: name, regexp: regexp, parse: parse, format: format }
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# (step_file) -> state: invoke the file's factory, or {} if none.
|
|
47
|
+
def context_factory
|
|
48
|
+
factories = @context_factories_by_file.dup
|
|
49
|
+
lambda do |step_file|
|
|
50
|
+
factory = factories[step_file]
|
|
51
|
+
factory ? factory.call : {}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Build a Core::Registry: custom parameter types first (so expressions
|
|
56
|
+
# can reference them), then steps in registration order.
|
|
57
|
+
def build_registry
|
|
58
|
+
registry = Core::Registries.create_registry
|
|
59
|
+
@custom_types.each do |type|
|
|
60
|
+
registry = Core::Registries.define_parameter_type(
|
|
61
|
+
registry, name: type[:name], regexp: type[:regexp], parse: type[:parse], format: type[:format]
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
@steps.each do |step|
|
|
65
|
+
registry = Core::Registries.add_step(
|
|
66
|
+
registry,
|
|
67
|
+
expression: step[:expression],
|
|
68
|
+
expression_source_file: step[:source_file],
|
|
69
|
+
expression_source_line: step[:source_line],
|
|
70
|
+
handler: step[:handler],
|
|
71
|
+
kind: step[:kind]
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
registry
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Clear all accumulated state (between isolated runs / harness bundles).
|
|
78
|
+
def reset_builder
|
|
79
|
+
@steps = []
|
|
80
|
+
@context_factories_by_file = {}
|
|
81
|
+
@custom_types = []
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Conformance-harness accessor: custom parameter types projected to the
|
|
85
|
+
# {"name","regexp"} wire shape. `regexp` is the bare source (Regexp#source
|
|
86
|
+
# or the string as authored) — the cross-port convention.
|
|
87
|
+
def custom_parameter_types
|
|
88
|
+
@custom_types.map do |type|
|
|
89
|
+
regexp = type[:regexp]
|
|
90
|
+
regexp = regexp.source if regexp.is_a?(Regexp)
|
|
91
|
+
unless regexp.is_a?(String)
|
|
92
|
+
raise "parameter type #{type[:name].inspect}: regexp arrays are not supported " \
|
|
93
|
+
'by the conformance projection yet'
|
|
94
|
+
end
|
|
95
|
+
{ 'name' => type[:name], 'regexp' => regexp }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# The block-scoped authoring DSL. A Builder is `instance_eval`-ed with the
|
|
101
|
+
# `steps` block, so authors write bare `stimulus`/`sensor`/`param` calls;
|
|
102
|
+
# each delegates to the accumulator above.
|
|
103
|
+
class Builder
|
|
104
|
+
def stimulus(expression, &handler)
|
|
105
|
+
Internal.add_step(expression, handler, 'stimulus')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def sensor(expression, &handler)
|
|
109
|
+
Internal.add_step(expression, handler, 'sensor')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def param(name, regexp, parse: nil, format: nil)
|
|
113
|
+
Internal.add_custom_type(name, regexp, parse, format)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'oselvar/var/internal'
|
|
4
|
+
|
|
5
|
+
module Oselvar
|
|
6
|
+
module Var
|
|
7
|
+
# Adapter/harness glue — mirrors the `@oselvar/var/registry` subpath.
|
|
8
|
+
# Authors import only `steps` (via oselvar/var); runners and the conformance
|
|
9
|
+
# harness reach the accumulator through here.
|
|
10
|
+
module RegistryGlue
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def reset_builder
|
|
14
|
+
Internal.reset_builder
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def build_registry
|
|
18
|
+
Internal.build_registry
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def context_factory
|
|
22
|
+
Internal.context_factory
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def custom_parameter_types
|
|
26
|
+
Internal.custom_parameter_types
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/oselvar/var.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'oselvar/var/core'
|
|
4
|
+
require 'oselvar/var/internal'
|
|
5
|
+
require 'oselvar/var/dsl'
|
|
6
|
+
|
|
7
|
+
module Oselvar
|
|
8
|
+
# The author facade: `steps` (top-level DSL) → [param, stimulus, sensor],
|
|
9
|
+
# backed by the module-scope accumulator in Internal.
|
|
10
|
+
module Var
|
|
11
|
+
VERSION = '0.3.2'
|
|
12
|
+
end
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: oselvar-var
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Aslak Hellesøy
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-07 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: cucumber-cucumber-expressions
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 20.0.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - '='
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 20.0.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: oselvar-var-core
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.3.2
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.3.2
|
|
41
|
+
description: 'The Vár author facade: define_state and the step-registration accumulator.'
|
|
42
|
+
email:
|
|
43
|
+
- aslak@oselvar.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- lib/oselvar/var.rb
|
|
49
|
+
- lib/oselvar/var/dsl.rb
|
|
50
|
+
- lib/oselvar/var/internal.rb
|
|
51
|
+
- lib/oselvar/var/registry.rb
|
|
52
|
+
homepage: https://var.oselvar.com
|
|
53
|
+
licenses:
|
|
54
|
+
- MIT
|
|
55
|
+
metadata:
|
|
56
|
+
rubygems_mfa_required: 'true'
|
|
57
|
+
post_install_message:
|
|
58
|
+
rdoc_options: []
|
|
59
|
+
require_paths:
|
|
60
|
+
- lib
|
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '3.2'
|
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
|
+
requirements:
|
|
68
|
+
- - ">="
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
version: '0'
|
|
71
|
+
requirements: []
|
|
72
|
+
rubygems_version: 3.4.10
|
|
73
|
+
signing_key:
|
|
74
|
+
specification_version: 4
|
|
75
|
+
summary: Markdown-native BDD — author API (define_state)
|
|
76
|
+
test_files: []
|