Module: Oselvar::Var::Runner::CLI

Defined in:
lib/oselvar/var/runner/cli.rb

Overview

The var command-line entry point (exposed by the exe/var executable). Today it offers a single sub-command, var init, which scaffolds a new project: a var.config.json, one Markdown spec, its step definitions, and a framework bridge that turns the specs into RSpec examples or Minitest tests.

The config, spec and steps mirror the TypeScript CLI (@oselvar/var-cli) so a project started with var init looks the same in every language; only the bridge is Ruby-specific, because RSpec/Minitest — unlike pytest — need an explicit generator call to discover the specs.

Constant Summary collapse

CONFIG =
<<~JSON
  {
    "docs": { "include": ["var-examples/**/*.md"], "exclude": [] },
    "steps": ["var-examples/**/*.steps.rb"]
  }
JSON
EXAMPLE_MD =
<<~MARKDOWN
  # Hello, BDD

  Given I greet "world"
  Then the greeting is "Hello, world!"
MARKDOWN
EXAMPLE_STEPS =
<<~RUBY
  # frozen_string_literal: true

  require 'oselvar/var'

  steps(greeting: '') do
    stimulus('I greet {string}') { |_state, name| { greeting: "Hello, \#{name}!" } }
    sensor('the greeting is {string}') { |state, _expected| state[:greeting] }
  end
RUBY
RSPEC_BRIDGE =
<<~RUBY
  # frozen_string_literal: true

  # Turn every Markdown spec matched by var.config.json into RSpec examples —
  # one `it` per Markdown example, discovered when this file loads.
  require 'oselvar/var/rspec'

  # var.config.json lives at the project root (the parent of spec/).
  Oselvar::Var::RSpec.generate(root: File.expand_path('..', __dir__))
RUBY
MINITEST_BRIDGE =
<<~RUBY
  # frozen_string_literal: true

  require 'minitest/autorun'
  require 'oselvar/var/minitest'

  # Turn every Markdown spec matched by var.config.json into Minitest tests —
  # var.config.json lives at the project root (the parent of test/).
  Oselvar::Var::Minitest.generate_tests(Object, root: File.expand_path('..', __dir__))
RUBY
USAGE =
<<~TEXT
  var — scaffold and run Markdown specs

  Usage:
    var init               scaffold a new project
TEXT

Class Method Summary collapse

Class Method Details

.detect_frameworkObject

RSpec when its adapter is installed, Minitest when only that one is, RSpec as the fallback (matching the tutorial's default track).



113
114
115
116
117
118
# File 'lib/oselvar/var/runner/cli.rb', line 113

def self.detect_framework
  return :rspec if gem_present?('oselvar-var-rspec')
  return :minitest if gem_present?('oselvar-var-minitest')

  :rspec
end

.gem_present?(name) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
# File 'lib/oselvar/var/runner/cli.rb', line 120

def self.gem_present?(name)
  Gem::Specification.find_all_by_name(name).any?
rescue StandardError
  false
end

.main(argv, cwd: Dir.pwd, out: $stdout) ⇒ Object



73
74
75
76
77
78
79
80
81
# File 'lib/oselvar/var/runner/cli.rb', line 73

def self.main(argv, cwd: Dir.pwd, out: $stdout)
  case argv.first
  when 'init'
    run_init(cwd, out)
  else
    out.print(USAGE)
    argv.empty? || %w[help -h --help].include?(argv.first) ? 0 : 1
  end
end

.run_init(cwd, out, framework: detect_framework) ⇒ Object

Write the scaffold into cwd, skipping any file that already exists. The framework bridge matches whichever adapter gem is installed (RSpec by default).



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/oselvar/var/runner/cli.rb', line 86

def self.run_init(cwd, out, framework: detect_framework)
  files = [
    ['var.config.json', CONFIG],
    ['var-examples/01-hello.md', EXAMPLE_MD],
    ['var-examples/steps/01-hello.steps.rb', EXAMPLE_STEPS]
  ]
  files << if framework == :minitest
             ['test/var_test.rb', MINITEST_BRIDGE]
           else
             ['spec/var_spec.rb', RSPEC_BRIDGE]
           end

  files.each do |rel, content|
    target = File.join(cwd, rel)
    if File.exist?(target)
      out.puts "skipped #{rel} (already exists)"
      next
    end
    FileUtils.mkdir_p(File.dirname(target))
    File.write(target, content)
    out.puts "created #{rel}"
  end
  0
end