speculate_about 0.2.3 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3d2e27062babfecbf03e34c59b76b495cbb1a9f27d3cbd0f4b23501d3be9181
4
- data.tar.gz: bdde751f7fa2c532dc95551f06ecc22f44fba32ad0f70103371e1743f62ca347
3
+ metadata.gz: b7194ffffa00a4292176dafa4120ea24ddf47e8aa6b6ed04d8be2dfaeefcfb8b
4
+ data.tar.gz: bb6b85091a5c9c59465f7df1f2369f33aa6e3090c249ee4cdc9184a9ef1580e3
5
5
  SHA512:
6
- metadata.gz: 95b2fd95e73b0b95d8c9237200bdb86c198f8584987d1f0a54968b742b46c1a06ffff29eb6352962a14e54c9d9d7e047a02f98c57b78a8894fc5c14a4f941d8c
7
- data.tar.gz: bc56ce52b6e4bc87fbff62c5fb5583ad6fe683b4dd78e18bc8b6d6da28bfbdedf46d3397e297c70878dff8633e3c8c0aa15cb89c871d01ff3c84a8c32c3ccf12
6
+ metadata.gz: 2e88641b31f6adf08b14730b619fbc31828f4d04b8058946cb1b9b71d7cecf05695d9d1b59849184b31220d88d7fd0d821e0b318f24cc68d803ed303cb792b97
7
+ data.tar.gz: 7de92ee9f101df89939eea6b8c0b42513d88222bbef60fa51fe2a9413add66e50b5f1da0ca7ff46d7ca02811b31be7ceb925c45509a3ad8c5dabb82fcc28f5e0
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/speculations/cli'
3
+
4
+ Speculations::CLI.run(ARGV)
@@ -1,2 +1,29 @@
1
- module Speculations
1
+ require 'fileutils'
2
+ require_relative 'speculations/parser'
3
+ module Speculations extend self
4
+
5
+ def compile(infile, outfile=nil)
6
+ raise ArgumentError, "#{infile} not found" unless File.readable? infile
7
+ outfile ||= _speculation_path(infile)
8
+ if _out_of_date?(outfile, infile)
9
+ ast = Speculations::Parser.new.parse_from_file(infile)
10
+ File.write(outfile, ast.to_code.join("\n"))
11
+ end
12
+ outfile
13
+ end
14
+
15
+ private
16
+
17
+ def _out_of_date?(outf, inf)
18
+ return true unless File.exists? outf
19
+ return File.lstat(outf).mtime <= File.lstat(inf).mtime
20
+ end
21
+
22
+ def _speculation_path(file)
23
+ dir = File.dirname(file)
24
+ dest_dir = File.join("spec", "speculations", dir)
25
+ FileUtils.mkdir_p(dest_dir) unless File.directory?(dest_dir)
26
+ rspec = File.basename(file, ".md")
27
+ File.join(dest_dir, "#{rspec}_spec.rb")
28
+ end
2
29
  end
@@ -0,0 +1,49 @@
1
+
2
+ module Speculations
3
+ module CLI extend self
4
+ def run args
5
+ loop do
6
+ case args.first
7
+ when "-h", "--help"
8
+ _usage
9
+ when "-v", "--version"
10
+ _version
11
+ else
12
+ return _compile_and_maybe_run args
13
+ end
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def _compile_and_maybe_run args
20
+ require_relative "../speculations"
21
+ args = Dir.glob(["*.md", "speculations/**/*.md"]) if args.empty?
22
+ args.each do |input_file|
23
+ Speculations.compile(input_file)
24
+ end
25
+ end
26
+
27
+ def _usage
28
+ puts <<-EOF
29
+ usage:
30
+ #{$0} [options] [filenames]
31
+
32
+ options:
33
+ -h | --help display this exit with -1
34
+ -v | --version display version of the speculate_about gem exit with -2
35
+
36
+ filenames (default to all markdown files in the project directory and its speculations subdirectories)
37
+
38
+ recreate outdated speculations in `spec/speculations/`
39
+ EOF
40
+ exit -1
41
+ end
42
+
43
+ def _version
44
+ require_relative 'version'
45
+ puts VERSION
46
+ exit -2
47
+ end
48
+ end
49
+ end
@@ -1,40 +1,39 @@
1
- require_relative '../speculations'
2
- class Speculations::Parser
3
- require_relative './parser/context'
4
- require_relative './parser/state'
1
+ module Speculations
2
+ class Parser
3
+ require_relative './parser/context'
4
+ require_relative './parser/state'
5
5
 
6
- attr_reader :filename, :input, :orig_filename, :root, :state
7
6
 
8
- def self.parsers
9
- @__parsers__ ||= {
10
- bef: State::Bef,
11
- exa: State::Exa,
12
- inc: State::Inc,
13
- out: State::Out
14
- }
15
- end
7
+ def self.parsers
8
+ @__parsers__ ||= {
9
+ candidate: State::Candidate,
10
+ in: State::In,
11
+ out: State::Out
12
+ }
13
+ end
16
14
 
17
- def parse_from_file file, orig_filename = nil
18
- @filename = file
19
- @orig_filename = orig_filename || file
20
- @input = File
21
- .new(file)
22
- .each_line(chomp: true)
23
- .lazy
24
- parse!
25
- end
15
+ def parse_from_file file
16
+ @filename = file
17
+ @input = File
18
+ .new(file)
19
+ .each_line(chomp: true)
20
+ .lazy
21
+ parse!
22
+ end
26
23
 
27
- private
24
+ private
28
25
 
29
- def initialize
30
- @state = :out
31
- end
26
+ def initialize
27
+ @state = :out
28
+ end
32
29
 
33
- def parse!
34
- root = node = Context.new(name: "Speculations from #{@filename}", lnb: 0, filename: @filename, orig_filename: orig_filename, parent: nil)
35
- input.each_with_index do |line, lnb|
36
- @state, node = self.class.parsers.fetch(@state).parse(line, lnb.succ, node)
30
+ def parse!
31
+ root = node = Context.new(filename: @filename)
32
+ ctxt = nil
33
+ @input.each_with_index do |line, lnb|
34
+ @state, node, ctxt = self.class.parsers.fetch(@state).parse(line, lnb.succ, node, ctxt)
35
+ end
36
+ root
37
37
  end
38
- root
39
38
  end
40
39
  end
@@ -1,90 +1,129 @@
1
- class Speculations::Parser::Context
2
- require_relative './context/include'
3
- require_relative './context/example'
4
- require_relative './context/setup'
5
-
6
- attr_reader :filename, :level, :lnb, :name, :orig_filename, :parent, :potential_name, :setup
7
-
8
- def add_child(name:, lnb:)
9
- raise "Illegal nesting" if parent
10
- children << self.class.new(name: name, lnb: lnb, parent: self)
11
- children.last
12
- end
13
-
14
- def add_example(lnb:, line:)
15
- examples << Example.new(lnb: lnb, parent: self, line: line, name: potential_name)
16
- @potential_name = nil
17
- examples.last
18
- end
19
-
20
- def add_include(lnb:)
21
- includes << Include.new(lnb: lnb, parent: self)
22
- includes.last
23
- end
24
-
25
- def children
26
- @__children__ ||= []
27
- end
28
-
29
- def examples
30
- @__examples__ ||= []
31
- end
32
-
33
- def includes
34
- @__includes__ ||= []
35
- end
36
-
37
- def map_lines(*lines, indent: 0)
38
- prefix = " " * (level + indent)
39
- lines.flatten.map{ |line| "#{prefix}#{line.strip}" }.join("\n")
40
- end
41
-
42
- def set_name(potential_name)
43
- @potential_name = potential_name
44
- end
45
-
46
- def set_setup(lnb:)
47
- @setup = Setup.new(lnb: lnb, parent: self)
48
- end
49
-
50
- def to_code
51
- [
52
- _header,
53
- includes.map(&:to_code),
54
- setup&.to_code,
55
- examples.map(&:to_code),
56
- children.map(&:to_code),
57
- _footer
58
- ].flatten.compact.join("\n")
59
- end
60
-
61
- private
62
-
63
- def initialize(lnb:, name:, filename: nil, orig_filename: nil, parent: nil)
64
- _init_from_parent filename, orig_filename, parent
65
- @level = parent ? parent.level.succ : 1
66
- @lnb = lnb
67
- @setup = nil
68
- @name = name
69
- @parent = parent
70
- end
71
-
72
- def _header
73
- map_lines(%{context "#{name}" do}, indent: -1)
1
+ module Speculations
2
+ class Parser
3
+ class Context
4
+ require_relative './context/include'
5
+ require_relative './context/example'
6
+
7
+ DISCLAIMER = <<-EOD
8
+ # DO NOT EDIT!!!
9
+ # This file was generated from FILENAME with the speculate_about gem, if you modify this file
10
+ # one of two bad things will happen
11
+ # - your documentation specs are not correct
12
+ # - your modifications will be overwritten by the speculate rake task
13
+ # YOU HAVE BEEN WARNED
14
+ EOD
15
+
16
+ attr_reader :filename, :level, :lnb, :title, :parent, :root, :tree_level
17
+
18
+ def new_context(title:, lnb:, level: )
19
+ new_child = self.class.new(title: title, lnb: lnb, parent: self, level: level)
20
+ _realign_levels(new_child)
21
+ end
22
+
23
+ def new_example(lnb:, title:)
24
+ examples << Example.new(lnb: lnb, parent: self, title: title)
25
+ examples.last
26
+ end
27
+
28
+ def new_include(lnb:)
29
+ includes << Include.new(lnb: lnb, parent: self)
30
+ includes.last
31
+ end
32
+
33
+ def parent_of_level needed_min_level
34
+ # I would love to write
35
+ # self.enum_by(:parent).find{ |ctxt| ctxt.level <= needed_min_level }
36
+ current = self
37
+ while current.level > needed_min_level
38
+ current = current.parent
39
+ end
40
+ current
41
+ end
42
+
43
+ def children
44
+ @__children__ ||= []
45
+ end
46
+
47
+ def examples
48
+ @__examples__ ||= []
49
+ end
50
+
51
+ def includes
52
+ @__includes__ ||= []
53
+ end
54
+
55
+ def map_lines(*lines, indent: 0)
56
+ prefix = " " * (tree_level + indent).succ
57
+ lines.flatten.map{ |line| "#{prefix}#{line.strip}" }
58
+ end
59
+
60
+ def to_code
61
+ [
62
+ _header,
63
+ includes.map(&:to_code),
64
+ examples.map(&:to_code),
65
+ children.map(&:to_code),
66
+ _footer
67
+ ].flatten.compact
68
+ end
69
+
70
+ def with_new_parent new_parent
71
+ @parent = new_parent
72
+ @tree_level += 1
73
+ self
74
+ end
75
+
76
+
77
+ private
78
+
79
+ def initialize(lnb: 0, title: nil, filename: nil, parent: nil, level: 0)
80
+ @filename = filename
81
+ @level = level
82
+ @lnb = lnb
83
+ @title = title
84
+ @parent = parent
85
+ if parent
86
+ _init_from_parent
87
+ else
88
+ @root = self
89
+ @tree_level = 0
90
+ end
91
+ end
92
+
93
+ def _header
94
+ if parent
95
+ map_lines(%{# #{filename}:#{lnb}}, %{context "#{title}" do}, indent: -1)
96
+ else
97
+ _root_header
98
+ end
99
+ end
100
+
101
+ def _root_header
102
+ map_lines(DISCLAIMER.gsub("FILENAME", filename.inspect).split("\n"), %{RSpec.describe #{filename.inspect} do}, indent: -1)
103
+ end
104
+
105
+ def _init_from_parent
106
+ @root = parent.root
107
+ @filename = parent.filename
108
+ @tree_level = parent.tree_level.succ
109
+ end
110
+
111
+ def _footer
112
+ map_lines("end", indent: -1)
113
+ end
114
+
115
+ def _realign_levels new_parent
116
+ if children.empty? || children.first.level == new_parent.level
117
+ children << new_parent
118
+ return new_parent
119
+ end
120
+ children.each do |child|
121
+ new_parent.children << child.with_new_parent(new_parent)
122
+ end
123
+ @__children__ = [new_parent]
124
+ new_parent
125
+ end
126
+
127
+ end
74
128
  end
75
-
76
- def _init_from_parent filename, orig_filename, parent
77
- _set_filename filename, orig_filename, parent
78
- @orig_filename = parent ? parent.orig_filename : orig_filename
79
- end
80
-
81
- def _set_filename filename, orig_filename, parent
82
- @filename = parent ? parent.filename : filename
83
- raise ArgumentError, "no filename given in root context" unless @filename
84
- end
85
-
86
- def _footer
87
- map_lines("end", indent: -1)
88
- end
89
-
90
129
  end
@@ -1,8 +1,7 @@
1
1
  class Speculations::Parser::Context::Example
2
2
 
3
- attr_reader :lnb, :name, :parent
3
+ attr_reader :lnb, :title, :parent
4
4
 
5
- NAMED_EXAMPLE = %r{\A[`~]{3,}ruby\s+:example\s+(.*)}
6
5
 
7
6
  def add_line line
8
7
  lines << line
@@ -15,34 +14,24 @@ class Speculations::Parser::Context::Example
15
14
 
16
15
  def to_code
17
16
  parent.map_lines(_example_head) +
18
- "\n" +
19
17
  parent.map_lines(lines, indent: 1) +
20
- "\n" +
21
18
  parent.map_lines("end")
22
19
  end
23
20
 
24
21
 
25
22
  private
26
23
 
27
- def initialize(lnb:, line:, parent:, name: nil)
24
+ def initialize(lnb:, parent:, title:)
28
25
  @lnb = lnb
29
26
  @parent = parent
30
- @name = _compute_name(lnb: lnb, line: line, parent: parent, name: name)
27
+ @title = _compute_title(title)
31
28
  end
32
29
 
33
- def _compute_name(lnb:, parent:, line:, name:)
34
- _, name1 = NAMED_EXAMPLE.match(line).to_a
35
-
36
- if name1&.empty? == false # SIC
37
- "#{name1} (#{parent.orig_filename}:#{lnb.succ})"
38
- elsif name
39
- "#{name} (#{parent.orig_filename}:#{lnb.succ})"
40
- else
41
- "Example from #{parent.orig_filename}:#{lnb.succ}"
42
- end
30
+ def _compute_title(title)
31
+ "#{title} (#{parent.root.filename}:#{lnb})"
43
32
  end
44
33
 
45
34
  def _example_head
46
- %{it "#{name}" do}
35
+ %{it "#{title}" do}
47
36
  end
48
37
  end
@@ -12,7 +12,7 @@ class Speculations::Parser::Context::Include
12
12
  end
13
13
 
14
14
  def to_code
15
- parent.map_lines(lines)
15
+ parent.map_lines("# #{parent.filename}:#{lnb}", lines)
16
16
  end
17
17
 
18
18
  private
@@ -1,39 +1,8 @@
1
1
  module Speculations::Parser::State extend self
2
- require_relative './state/bef'
3
- require_relative './state/exa'
4
- require_relative './state/inc'
2
+ require_relative './state/candidate'
3
+ require_relative './state/in'
5
4
  require_relative './state/out'
5
+ require_relative './state/triggers'
6
6
 
7
- BEFORE_RGX = %r[\A\s{0,3}```.*\s:before]
8
- CONTEXT_RGX = %r[\A\s{0,3}\#{1,7}\s+Context\s+(.*)]
9
- EOBLOCK_RGX = %r[\A\s{0,3}```\s*\z]
10
- EXAMPLE_RGX = %r[\A\s{0,3}```.*\s:example]
11
- INCLUDE_RGX = %r[\A\s{0,3}```.*\s:include]
12
- NAME_RGX = %r[\A\s{0,3}Example:\s+(.*)]
13
-
14
- def before_match line
15
- BEFORE_RGX =~ line
16
- end
17
-
18
- def context_match line
19
- if match = CONTEXT_RGX.match(line)
20
- match.captures.first
21
- end
22
- end
23
-
24
- def eoblock_match line
25
- EOBLOCK_RGX =~ line
26
- end
27
-
28
- def example_match line
29
- EXAMPLE_RGX =~ line
30
- end
31
-
32
- def include_match line
33
- INCLUDE_RGX =~ line
34
- end
35
-
36
- def potential_name line
37
- NAME_RGX.match(line)
38
- end
7
+ extend Triggers
39
8
  end
@@ -0,0 +1,32 @@
1
+ module Speculations
2
+ class Parser
3
+ module State
4
+ module Candidate extend self
5
+ def parse line, lnb, node, ctxt
6
+ case
7
+ when State.blank_line(line)
8
+ [:candidate, node, ctxt]
9
+ when match = State.context_match(line)
10
+ level = match[1].size
11
+ new_parent = node.parent_of_level(level.pred)
12
+ node = new_parent.new_context(title: match[2], lnb: lnb, level: level)
13
+ [:out, node]
14
+ when match = State.maybe_example(line)
15
+ [:candidate, node, match[:title]]
16
+ when match = State.maybe_include(line)
17
+ [:candidate, node, :inc]
18
+ when match = State.ruby_code_block(line)
19
+ if ctxt == :inc
20
+ node = node.new_include(lnb: lnb)
21
+ else
22
+ node = node.new_example(title: ctxt, lnb: lnb)
23
+ end
24
+ [:in, node]
25
+ else
26
+ [:out, node]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,14 +1,14 @@
1
1
  module Speculations
2
2
  class Parser
3
3
  module State
4
- module Inc extend self
4
+ module In extend self
5
5
 
6
- def parse line, _lnb, node
6
+ def parse line, _lnb, node, ctxt
7
7
  case
8
8
  when State.eoblock_match(line)
9
9
  [:out, node.parent]
10
10
  else
11
- [:inc, node.add_line(line)]
11
+ [:in, node.add_line(line)]
12
12
  end
13
13
  end
14
14
  end
@@ -3,29 +3,28 @@ module Speculations
3
3
  module State
4
4
  module Out extend self
5
5
 
6
- def parse line, lnb, node
6
+ def parse line, lnb, node, _ctxt
7
7
  case
8
- when name = State.context_match(line)
9
- node = node.parent if node.parent
10
- new_node = node.add_child(name: name, lnb: lnb)
11
- [:out, new_node]
12
- when State.before_match(line)
13
- node = node.set_setup(lnb: lnb)
14
- [:bef, node]
15
- when State.example_match(line)
16
- node = node.add_example(lnb: lnb, line: line)
17
- [:exa, node]
18
- when State.include_match(line)
19
- node = node.add_include(lnb: lnb)
20
- [:inc, node]
21
- when name = State.potential_name(line)
22
- node.set_name(name[1])
23
- [:out, node]
8
+ when match = State.context_match(line)
9
+ make_new_context(lnb: lnb, node: node, match: match)
10
+ when match = State.maybe_example(line)
11
+ [:candidate, node, match[:title]]
12
+ when match = State.maybe_include(line)
13
+ [:candidate, node, :inc]
24
14
  else
25
15
  [:out, node]
26
16
  end
27
17
  end
28
18
 
19
+ private
20
+
21
+ def make_new_context(lnb:, match:, node:)
22
+ level = match[:level].size
23
+ new_parent = node.parent_of_level(level.pred)
24
+ node = new_parent.new_context(title: match[:title], lnb: lnb, level: level)
25
+ [:out, node]
26
+ end
27
+
29
28
  end
30
29
  end
31
30
  end
@@ -0,0 +1,35 @@
1
+ module Speculations::Parser::State::Triggers
2
+
3
+ BLANK_RGX = %r{\A\s*\z}
4
+ CONTEXT_RGX = %r[\A\s{0,3}(?<level>\#{1,7})\s+Context:?\s+(?<title>.*)]
5
+ EOBLOCK_RGX = %r[\A\s{0,3}```\s*\z]
6
+ GIVEN_RGX = %r[\A\s{0,3}(?:Given|When)\b]
7
+ EXAMPLE_RGX = %r[\A\s{0,3}Example:?\s+(<?title>.*)]
8
+ RUBY_RGX = %r[\A\s{0,3}```ruby]
9
+ THEN_RGX = %r[\A\s{0,3}(?:Then|But|And|Also)\b\s*(?<title>.*)]
10
+
11
+ def blank_line line
12
+ BLANK_RGX.match(line)
13
+ end
14
+
15
+ def context_match line
16
+ CONTEXT_RGX.match(line)
17
+ end
18
+
19
+ def eoblock_match line
20
+ EOBLOCK_RGX.match(line)
21
+ end
22
+
23
+ def maybe_example line
24
+ EXAMPLE_RGX.match(line) ||
25
+ THEN_RGX.match(line)
26
+ end
27
+
28
+ def maybe_include line
29
+ GIVEN_RGX.match(line)
30
+ end
31
+
32
+ def ruby_code_block line
33
+ RUBY_RGX.match(line)
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
- module SpeculateAbout
2
- VERSION = "0.2.3"
1
+ module Speculations
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,54 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: speculate_about
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Dober
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-12 00:00:00.000000000 Z
11
+ date: 2021-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '3.9'
33
+ version: '3.10'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '3.9'
40
+ version: '3.10'
27
41
  description: Allows Markdown or other text files to be used as literal specs, à la
28
42
  Elixr doctest, but from any file.
29
43
  email: robert.dober@gmail.com
30
- executables: []
44
+ executables:
45
+ - speculate
31
46
  extensions: []
32
47
  extra_rdoc_files: []
33
48
  files:
34
- - lib/speculate_about.rb
49
+ - bin/speculate
35
50
  - lib/speculations.rb
51
+ - lib/speculations/cli.rb
36
52
  - lib/speculations/parser.rb
37
53
  - lib/speculations/parser/context.rb
38
54
  - lib/speculations/parser/context/example.rb
39
55
  - lib/speculations/parser/context/include.rb
40
- - lib/speculations/parser/context/setup.rb
41
56
  - lib/speculations/parser/state.rb
42
- - lib/speculations/parser/state/bef.rb
43
- - lib/speculations/parser/state/exa.rb
44
- - lib/speculations/parser/state/inc.rb
57
+ - lib/speculations/parser/state/candidate.rb
58
+ - lib/speculations/parser/state/in.rb
45
59
  - lib/speculations/parser/state/out.rb
60
+ - lib/speculations/parser/state/triggers.rb
46
61
  - lib/speculations/version.rb
47
62
  homepage: https://github.com/robertdober/speculate
48
63
  licenses:
49
64
  - Apache-2.0
50
65
  metadata: {}
51
- post_install_message:
66
+ post_install_message:
52
67
  rdoc_options: []
53
68
  require_paths:
54
69
  - lib
@@ -63,8 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
78
  - !ruby/object:Gem::Version
64
79
  version: '0'
65
80
  requirements: []
66
- rubygems_version: 3.1.2
67
- signing_key:
81
+ rubygems_version: 3.2.3
82
+ signing_key:
68
83
  specification_version: 4
69
84
  summary: Extract RSpecs from Markdown
70
85
  test_files: []
@@ -1,45 +0,0 @@
1
- require 'rspec'
2
-
3
- require 'speculations/parser'
4
-
5
- module SpeculateAbout
6
- def speculate_about file
7
- paths = _find_files(file, File.dirname( caller.first ))
8
- raise ArgumentError, "no files found for pattern #{file}" if paths.empty?
9
- paths.each do |path|
10
- code = _compile path, _readable(path)
11
- ENV["SPECULATE_ABOUT_DEBUG"] ? _show(code, path) : instance_eval(code, path)
12
- end
13
- end
14
-
15
-
16
- private
17
-
18
- def _compile path, file
19
- ast = Speculations::Parser.new.parse_from_file(path, file)
20
- ast.to_code
21
- end
22
- def _readable(path)
23
- d = File.dirname(path)
24
- File.join(File.basename(d), File.basename(path))
25
- end
26
- def _find_files file, local_path
27
- [Dir.pwd, local_path]
28
- .flat_map do |dir|
29
- Dir.glob(File.join(dir, file))
30
- end
31
- end
32
- def _show(code, path)
33
- message = "Generated code for #{path}"
34
- _underline(message)
35
- puts code
36
- end
37
- def _underline(message, ul: "=")
38
- puts message
39
- puts message.gsub(/./, ul)
40
- end
41
- end
42
-
43
- RSpec.configure do |conf|
44
- conf.extend SpeculateAbout
45
- end
@@ -1,28 +0,0 @@
1
- class Speculations::Parser::Context::Setup
2
-
3
- attr_reader :lnb, :parent
4
-
5
- def add_line line
6
- lines << line
7
- self
8
- end
9
-
10
- def lines
11
- @__lines__ ||= []
12
- end
13
-
14
- def to_code
15
- parent.map_lines("before do") +
16
- "\n" +
17
- parent.map_lines(lines, indent: 1) +
18
- "\n" +
19
- parent.map_lines("end")
20
- end
21
-
22
-
23
- private
24
-
25
- def initialize(lnb:, parent:)
26
- @parent = parent
27
- end
28
- end
@@ -1,17 +0,0 @@
1
- module Speculations
2
- class Parser
3
- module State
4
- module Bef extend self
5
-
6
- def parse line, _lnb, node
7
- case
8
- when State.eoblock_match(line)
9
- [:out, node.parent]
10
- else
11
- [:bef, node.add_line(line)]
12
- end
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- module Speculations
2
- class Parser
3
- module State
4
- module Exa extend self
5
-
6
- def parse line, _lnb, node
7
- case
8
- when State.eoblock_match(line)
9
- [:out, node.parent]
10
- else
11
- [:exa, node.add_line(line)]
12
- end
13
- end
14
- end
15
- end
16
- end
17
- end