speculate_about 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 669757a09c549512732274147c0b65dc3d71c3446b73490f961ae61b4e6a7d2b
4
- data.tar.gz: 68b1e0f9babc9630616b14b16bf5ad60a9974983495dc7c575287dfbb29472a0
3
+ metadata.gz: a40862f65330fcfdc48e0b22fb9a09447269ecad7ca0582522ecda4450b3257a
4
+ data.tar.gz: a65d170a63cdd08c0dfa711854beaf876a5810d84f9a82eab489ffcaa0331e57
5
5
  SHA512:
6
- metadata.gz: 4253cedda25c3f32eaf71b0bbe5a99376f05e42e1dd8ab1e4ca818d12f99d6ac88404883ba25e74318d4de094d4614bad63ac397cde6f71f2835d32109586e5e
7
- data.tar.gz: 2766bdc6aafb5f70c7ab73ec3b24e82ef025f6bbdfefd95de4d1bc797478de37de60ee60ff50c2895ead4c22e03117f432b6924252abae42419de5f46cf26ab9
6
+ metadata.gz: 1c42854aae7633c76e4d4cb8ce663915b55c48529833920252c3f2b57546cbe59490940db5c375a7468fede051cb237510255c3e5894b9e3ab87aa1feda126e1
7
+ data.tar.gz: 9c0e44f422c8638346fb416a3b4451a7a17001f1f9db08e70dbf4ed526b5b377fca96fb54ab9b1b3354d9fbbe91e2b97dde1b0bf15f2a261eec697677f7bc030
@@ -3,24 +3,40 @@ require 'rspec'
3
3
  require 'speculations/parser'
4
4
 
5
5
  module SpeculateAbout
6
- def speculate_about file
7
- path = _find_file(file, File.dirname( caller.first ))
8
- code = _compile path, file
9
- ENV["SPECULATE_ABOUT_DEBUG"] ? puts(code) : instance_eval(code)
6
+ def speculate_about file, alternate_syntax: false
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), alternate_syntax: alternate_syntax
11
+ ENV["SPECULATE_ABOUT_DEBUG"] ? _show(code, path) : instance_eval(code, path)
12
+ end
10
13
  end
11
14
 
12
15
 
13
16
  private
14
17
 
15
- def _compile path, file
16
- ast = Speculations::Parser.new.parse_from_file(path, file)
18
+ def _compile path, file, alternate_syntax: false
19
+ ast = Speculations::Parser.new.parse_from_file(path, file, alternate_syntax: alternate_syntax)
17
20
  ast.to_code
18
21
  end
19
- def _find_file file, local_path
20
- return file if File.readable? file
21
- local_file = File.join(local_path, file)
22
- return local_file if File.readable? local_file
23
- raise ArgumentError, "file #{file.inspect} not found"
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)
24
40
  end
25
41
  end
26
42
 
@@ -3,7 +3,7 @@ class Speculations::Parser
3
3
  require_relative './parser/context'
4
4
  require_relative './parser/state'
5
5
 
6
- attr_reader :filename, :input, :orig_filename, :root, :state
6
+ attr_reader :alternate_syntax, :filename, :input, :orig_filename, :root, :state
7
7
 
8
8
  def self.parsers
9
9
  @__parsers__ ||= {
@@ -14,7 +14,8 @@ class Speculations::Parser
14
14
  }
15
15
  end
16
16
 
17
- def parse_from_file file, orig_filename = nil
17
+ def parse_from_file file, orig_filename = nil, alternate_syntax: false
18
+ @alternate_syntax = alternate_syntax
18
19
  @filename = file
19
20
  @orig_filename = orig_filename || file
20
21
  @input = File
@@ -31,7 +32,7 @@ class Speculations::Parser
31
32
  end
32
33
 
33
34
  def parse!
34
- root = node = Context.new(name: "Speculations from #{@filename}", lnb: 0, filename: @filename, orig_filename: orig_filename, parent: nil)
35
+ root = node = Context.new(alternate_syntax: alternate_syntax, name: "Speculations from #{@filename}", lnb: 0, filename: @filename, orig_filename: orig_filename, parent: nil)
35
36
  input.each_with_index do |line, lnb|
36
37
  @state, node = self.class.parsers.fetch(@state).parse(line, lnb.succ, node)
37
38
  end
@@ -3,22 +3,23 @@ class Speculations::Parser::Context
3
3
  require_relative './context/example'
4
4
  require_relative './context/setup'
5
5
 
6
- attr_reader :filename, :level, :lnb, :name, :orig_filename, :parent, :potential_name, :setup
6
+ attr_reader :alternate_syntax, :filename, :level, :lnb, :name, :orig_filename, :parent, :potential_name, :setup
7
7
 
8
8
  def add_child(name:, lnb:)
9
9
  raise "Illegal nesting" if parent
10
- children << self.class.new(name: name, lnb: lnb, parent: self)
10
+ children << self.class.new(alternate_syntax: alternate_syntax, name: name, lnb: lnb, parent: self)
11
11
  children.last
12
12
  end
13
13
 
14
14
  def add_example(lnb:, line:)
15
15
  examples << Example.new(lnb: lnb, parent: self, line: line, name: potential_name)
16
- @potential_name = nil
16
+ reset_context
17
17
  examples.last
18
18
  end
19
19
 
20
20
  def add_include(lnb:)
21
21
  includes << Include.new(lnb: lnb, parent: self)
22
+ @given = false
22
23
  includes.last
23
24
  end
24
25
 
@@ -30,6 +31,10 @@ class Speculations::Parser::Context
30
31
  @__examples__ ||= []
31
32
  end
32
33
 
34
+ def given?
35
+ @given
36
+ end
37
+
33
38
  def includes
34
39
  @__includes__ ||= []
35
40
  end
@@ -39,8 +44,20 @@ class Speculations::Parser::Context
39
44
  lines.flatten.map{ |line| "#{prefix}#{line.strip}" }.join("\n")
40
45
  end
41
46
 
47
+ def reset_context
48
+ @potential_name = nil
49
+ @given = false
50
+ self
51
+ end
52
+
53
+ def set_given given
54
+ @given = given
55
+ self
56
+ end
57
+
42
58
  def set_name(potential_name)
43
59
  @potential_name = potential_name
60
+ self
44
61
  end
45
62
 
46
63
  def set_setup(lnb:)
@@ -60,8 +77,10 @@ class Speculations::Parser::Context
60
77
 
61
78
  private
62
79
 
63
- def initialize(lnb:, name:, filename: nil, orig_filename: nil, parent: nil)
80
+ def initialize(alternate_syntax: false, lnb:, name:, filename: nil, orig_filename: nil, parent: nil)
64
81
  _init_from_parent filename, orig_filename, parent
82
+ @alternate_syntax = alternate_syntax
83
+ @given = false
65
84
  @level = parent ? parent.level.succ : 1
66
85
  @lnb = lnb
67
86
  @setup = nil
@@ -74,8 +93,12 @@ class Speculations::Parser::Context
74
93
  end
75
94
 
76
95
  def _init_from_parent filename, orig_filename, parent
77
- @filename = parent ? parent.filename : filename
96
+ _set_filename filename, orig_filename, parent
78
97
  @orig_filename = parent ? parent.orig_filename : orig_filename
98
+ end
99
+
100
+ def _set_filename filename, orig_filename, parent
101
+ @filename = parent ? parent.filename : filename
79
102
  raise ArgumentError, "no filename given in root context" unless @filename
80
103
  end
81
104
 
@@ -8,8 +8,12 @@ module Speculations::Parser::State extend self
8
8
  CONTEXT_RGX = %r[\A\s{0,3}\#{1,7}\s+Context\s+(.*)]
9
9
  EOBLOCK_RGX = %r[\A\s{0,3}```\s*\z]
10
10
  EXAMPLE_RGX = %r[\A\s{0,3}```.*\s:example]
11
+ GIVEN_RGX = %r[\A\s{0,3}(?:Given|When)\b]
11
12
  INCLUDE_RGX = %r[\A\s{0,3}```.*\s:include]
12
- NAME_RGX = %r[\A\s{0,3}Example:\s+(.*)]
13
+ NAME_RGX = %r[\A\s{0,3}Example:?\s+(.*)]i
14
+ RUBY_RGX = %r[\A\s{0,3}```ruby]
15
+ THEN_RGX = %r[\A\s{0,3}Then\s+(.*)]
16
+ WS_RGX = %r[\A\s*\z]
13
17
 
14
18
  def before_match line
15
19
  BEFORE_RGX =~ line
@@ -28,6 +32,10 @@ module Speculations::Parser::State extend self
28
32
  def example_match line
29
33
  EXAMPLE_RGX =~ line
30
34
  end
35
+
36
+ def given_match line
37
+ GIVEN_RGX =~ line
38
+ end
31
39
 
32
40
  def include_match line
33
41
  INCLUDE_RGX =~ line
@@ -36,4 +44,16 @@ module Speculations::Parser::State extend self
36
44
  def potential_name line
37
45
  NAME_RGX.match(line)
38
46
  end
47
+
48
+ def ruby_match line
49
+ RUBY_RGX =~ line
50
+ end
51
+
52
+ def then_match line
53
+ THEN_RGX.match(line)
54
+ end
55
+
56
+ def ws_match line
57
+ WS_RGX =~ line
58
+ end
39
59
  end
@@ -4,6 +4,49 @@ module Speculations
4
4
  module Out extend self
5
5
 
6
6
  def parse line, lnb, node
7
+ if node.alternate_syntax
8
+ _parse_alternate line, lnb, node
9
+ else
10
+ _parse_classical line, lnb, node
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def _parse_alternate line, lnb, node
17
+ case
18
+ when name = State.context_match(line)
19
+ node = node.parent if node.parent
20
+ new_node = node.add_child(name: name, lnb: lnb)
21
+ [:out, new_node.reset_context]
22
+ when State.ws_match(line)
23
+ [:out, node]
24
+ when name = State.potential_name(line)
25
+ node.set_name(name[1])
26
+ node.set_given(false)
27
+ [:out, node]
28
+ when name = State.then_match(line)
29
+ node.set_name(name[1])
30
+ node.set_given(false)
31
+ [:out, node]
32
+ when State.given_match(line)
33
+ [:out, node.set_given(true)]
34
+ when State.ruby_match(line)
35
+ if node.potential_name
36
+ node = node.add_example(lnb: lnb, line: line)
37
+ [:exa, node]
38
+ elsif node.given?
39
+ node = node.add_include(lnb: lnb)
40
+ [:inc, node]
41
+ else
42
+ [:out, node]
43
+ end
44
+ else
45
+ [:out, node.reset_context]
46
+ end
47
+ end
48
+
49
+ def _parse_classical line, lnb, node
7
50
  case
8
51
  when name = State.context_match(line)
9
52
  node = node.parent if node.parent
@@ -0,0 +1,3 @@
1
+ module SpeculateAbout
2
+ VERSION = "0.4.0"
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: speculate_about
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.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-06-23 00:00:00.000000000 Z
11
+ date: 2020-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.9'
27
- description: Allows Markdown or other text files to be used as literal specs, a la
27
+ description: Allows Markdown or other text files to be used as literal specs, à la
28
28
  Elixr doctest, but from any file.
29
29
  email: robert.dober@gmail.com
30
30
  executables: []
@@ -43,11 +43,12 @@ files:
43
43
  - lib/speculations/parser/state/exa.rb
44
44
  - lib/speculations/parser/state/inc.rb
45
45
  - lib/speculations/parser/state/out.rb
46
+ - lib/speculations/version.rb
46
47
  homepage: https://github.com/robertdober/speculate
47
48
  licenses:
48
49
  - Apache-2.0
49
50
  metadata: {}
50
- post_install_message:
51
+ post_install_message:
51
52
  rdoc_options: []
52
53
  require_paths:
53
54
  - lib
@@ -63,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
64
  version: '0'
64
65
  requirements: []
65
66
  rubygems_version: 3.1.2
66
- signing_key:
67
+ signing_key:
67
68
  specification_version: 4
68
69
  summary: Extract RSpecs from Markdown
69
70
  test_files: []