rspec_tree 0.1.6 → 0.2.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: fc85df0dd2b82d08ccda1a27d0f6b23a779bac0df99f33eec75f45dd5d99abbe
4
- data.tar.gz: fae13802971ba1a4bc7f8b3af835adcb5708931f37618c9f4613ed0bd5c25a64
3
+ metadata.gz: b274e69832e65ed946b50548b72cbbd0cebb08f736d1f08a3de9e3a3841773bf
4
+ data.tar.gz: 3e9183e5707288dcd67c4ad580c1967ce839fad9c072a324a07a7e72ac19c83a
5
5
  SHA512:
6
- metadata.gz: 69547316a54ede78c5e72a246fd39c6114e064088db76bd4543d659322cec2dc0d7719eee50db5edc448f14641dd5886ba5ee19b7b0d3b02864fd980a9d1deca
7
- data.tar.gz: dc40926bf1390ca5e4b350d4420d7201fb87217621a0607081589cf0398932daaeae38a9f379315ce5adddbccd3dfa0e7d7873367c1e5f2f845d3c86d801fd1a
6
+ metadata.gz: 2b6ffed12d9068beae9a87a753c09965f0fac1e9b9f9d5676564ac6ad8a092bc861e522523e6cded0a42454a09eafa9dcb74b046c7e47fe5b8fa1e78ebbff957
7
+ data.tar.gz: 9c4481673679ab6cbde600495df838cdfb7e54715aa2fa8e80b73475154e85b79884ed09d340681aee616e8da0d7ba954c5a71e2743f087c2b216806bbde7760
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 3.3.1
3
3
 
4
4
  Style/StringLiterals:
5
5
  Enabled: true
@@ -11,3 +11,14 @@ Style/StringLiteralsInInterpolation:
11
11
 
12
12
  Layout/LineLength:
13
13
  Max: 120
14
+
15
+ Style/Documentation:
16
+ Enabled: false
17
+
18
+ Metrics/AbcSize:
19
+ Max: 30
20
+
21
+ Metrics/BlockLength:
22
+ Exclude:
23
+ - "spec/**/*"
24
+ - "config/routes.rb"
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2024-12-31
4
+
5
+ - Refactor to use prism parser
6
+
3
7
  ## [0.1.6] - 2024-03-25
4
8
 
5
9
  - Fix SyntaxError
@@ -28,4 +32,3 @@
28
32
  ## [0.1.0] - 2024-03-07
29
33
 
30
34
  - Initial release
31
-
data/Gemfile CHANGED
@@ -10,3 +10,5 @@ gem "rake", "~> 13.0"
10
10
  gem "rspec", "~> 3.0"
11
11
 
12
12
  gem "rubocop", "~> 1.21"
13
+
14
+ gem "prism", "~> 1.3.0"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec_tree (0.1.6)
4
+ rspec_tree (0.2.0)
5
5
  thor
6
6
 
7
7
  GEM
@@ -15,6 +15,7 @@ GEM
15
15
  parser (3.3.0.5)
16
16
  ast (~> 2.4.1)
17
17
  racc
18
+ prism (1.3.0)
18
19
  racc (1.7.3)
19
20
  rainbow (3.1.1)
20
21
  rake (13.1.0)
@@ -56,6 +57,7 @@ PLATFORMS
56
57
  x86_64-linux
57
58
 
58
59
  DEPENDENCIES
60
+ prism (~> 1.3.0)
59
61
  rake (~> 13.0)
60
62
  rspec (~> 3.0)
61
63
  rspec_tree!
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RspecTree
2
2
 
3
- This is tree command for rspec test files.
3
+ `RspecTree` is a command-line tool for displaying the structure of RSpec test files in a tree format. It uses [prism](https://github.com/ruby/prism), the default parser introduced in Ruby 3.4, to parse and traverse the AST.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,31 +14,42 @@ If bundler is not being used to manage dependencies, install the gem by executin
14
14
 
15
15
  ## Usage
16
16
 
17
- ```
17
+ ### Display All Describes, Contexts, and Examples
18
+
19
+ Use the `all` option to print all `describe`, `context`, and `example` blocks in a file:
20
+
21
+ ```bash
18
22
  $ rspec_tree all /path/to/your_spec.rb
19
- desc: Sample
20
- desc: First describe
21
- ├─────ctx: First context
22
- ├───────it: should do something
23
- ├───────ctx: First nested context
24
- ├─────────it: should do something
25
- ├───────it_behaves_like: shared example
26
- desc: Second describe
27
- ├─────ctx: Second context
28
- ├───────it: should do something else
23
+ desc: SampleClass
24
+ ├──desc: First describe
25
+ ├────ctx: First context
26
+ ├──────ctx: First nested context
27
+ ├────────it: should do something
28
+ ├──────it: should do something
29
+ ├──desc: Second describe
30
+ ├────ctx: Second context
31
+ ├──────it: should do something else
29
32
  ```
30
33
 
31
- ```
34
+ ### Display Only Describes and Contexts
35
+
36
+ Use the `ctx` option to print only `describe` and `context` blocks:
37
+
38
+ ```bash
32
39
  $ rspec_tree ctx /path/to/your_spec.rb
33
- desc: Sample
34
- desc: First describe
35
- ├─────ctx: First context
36
- ├───────ctx: First nested context
37
- desc: Second describe
38
- ├─────ctx: Second context
40
+ desc: SampleClass
41
+ ├──desc: First describe
42
+ ├────ctx: First context
43
+ ├──────ctx: First nested context
44
+ ├──desc: Second describe
45
+ ├────ctx: Second context
39
46
  ```
40
47
 
41
- ```
48
+ ### Display Help Information
49
+
50
+ Run the `help` command to see all available commands:
51
+
52
+ ```bash
42
53
  $ rspec_tree help
43
54
  Commands:
44
55
  rspec_tree all [file] # Print all (describe, context, it, etc.)
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "thor"
4
4
  require "rspec_tree/tree"
5
+ require "rspec_tree/visitor"
5
6
 
6
7
  module RspecTree
7
8
  # This class is used to define the CLI
@@ -9,14 +10,18 @@ module RspecTree
9
10
  desc "all [file]", "Print all (describe, context, it, etc.)"
10
11
  def all(file)
11
12
  File.open(file, "r") do |f|
12
- Tree.new(f.read, :all).print
13
+ visitor = RspecTree::Visitor.new
14
+ Prism.parse(f.read).value.accept(visitor)
15
+ RspecTree::Tree.new(visitor.root, :all).print
13
16
  end
14
17
  end
15
18
 
16
19
  desc "ctx [file]", "Print only describe and context"
17
20
  def ctx(file)
18
21
  File.open(file, "r") do |f|
19
- Tree.new(f.read, :ctx).print
22
+ visitor = RspecTree::Visitor.new
23
+ Prism.parse(f.read).value.accept(visitor)
24
+ RspecTree::Tree.new(visitor.root, :ctx).print
20
25
  end
21
26
  end
22
27
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RspecTree
4
+ class Context
5
+ attr_accessor :title, :contexts, :examples
6
+
7
+ def initialize
8
+ @title = nil
9
+ @contexts = []
10
+ @examples = []
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RspecTree
4
+ class Description
5
+ attr_accessor :title, :contexts
6
+
7
+ def initialize
8
+ @title = nil
9
+ @contexts = []
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RspecTree
4
+ class Example
5
+ attr_accessor :title
6
+
7
+ def initialize
8
+ @title = nil
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RspecTree
4
+ class Root
5
+ attr_accessor :title, :descriptions
6
+
7
+ def initialize
8
+ @title = nil
9
+ @descriptions = []
10
+ end
11
+ end
12
+ end
@@ -1,63 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "tree/rspec"
4
- require_relative "tree/monkey_patch"
5
-
6
3
  module RspecTree
7
- # This module is used to parse the RSpec file
8
- # and print the tree structure of the RSpec file.
9
4
  class Tree
10
- attr_reader :file, :type
11
- attr_accessor :base_depth
12
-
13
- PATTERN = /'*[::]*[A-Z][\w-]*(?:::[A-Z][\w-]*)+'*/.freeze
14
-
15
- def initialize(file, type)
16
- @file = const_to_string(file)
5
+ def initialize(root, type)
6
+ @root = root
17
7
  @type = type
18
- @base_depth = 0
19
8
  end
20
9
 
21
10
  def print
22
- eval(file) # rubocop:disable Security/Eval
11
+ print_root_description(@root, 0)
23
12
  end
24
13
 
25
14
  private
26
15
 
27
- def describe(*args, &block)
28
- self.base_depth = caller.size
29
- RSpec.describe(*args, &block)
30
- end
16
+ def print_root_description(description, depth)
17
+ puts "desc: #{description.title}"
31
18
 
32
- def context(*args, &block)
33
- tree(args.first, "ctx")
34
- block.call
19
+ description.descriptions.each do |nested_description|
20
+ print_description(nested_description, depth + 1)
21
+ end
35
22
  end
36
23
 
37
- def example(*args, &_block)
38
- tree(args.first, "ex")
39
- end
24
+ def print_description(description, depth)
25
+ puts "#{indent(depth)}desc: #{description.title}"
40
26
 
41
- def it(*args, &_block)
42
- tree(args.first, "it") if type == :all
27
+ description.contexts.each do |context|
28
+ print_context(context, depth + 1)
29
+ end
43
30
  end
44
31
 
45
- def it_behaves_like(*args, &_block)
46
- tree(args.first, "it_behaves_like") if type == :all
47
- end
32
+ def print_context(context, depth)
33
+ puts "#{indent(depth)}ctx: #{context.title}"
34
+
35
+ context.contexts.each do |ctx|
36
+ print_context(ctx, depth + 1)
37
+ end
48
38
 
49
- def dash
50
- "─" * (caller.size - base_depth)
39
+ context.examples.each do |example|
40
+ print_example(example, depth + 1)
41
+ end
51
42
  end
52
43
 
53
- def tree(arg, name)
54
- puts "├#{dash}#{name}: #{arg}"
44
+ def print_example(example, depth)
45
+ return if @type == :ctx
46
+
47
+ puts "#{indent(depth)}it: #{example.title}"
55
48
  end
56
49
 
57
- def const_to_string(str)
58
- str.gsub(PATTERN) do |match|
59
- "\"#{match}\""
60
- end
50
+ def indent(level)
51
+ "\u251C#{"\u2500\u2500" * level}"
61
52
  end
62
53
  end
63
54
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RspecTree
4
- VERSION = "0.1.6"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "prism"
4
+
5
+ require_relative "root"
6
+ require_relative "description"
7
+ require_relative "context"
8
+ require_relative "example"
9
+
10
+ module RspecTree
11
+ class Visitor < Prism::Visitor
12
+ attr_accessor :root
13
+
14
+ def initialize
15
+ @root = RspecTree::Root.new
16
+ super
17
+ end
18
+
19
+ def call_node?(node)
20
+ node.is_a?(Prism::CallNode)
21
+ end
22
+
23
+ def block_node?(node)
24
+ node.is_a?(Prism::BlockNode)
25
+ end
26
+
27
+ def root_describe_node?(node)
28
+ node&.name == :describe && node.receiver
29
+ end
30
+
31
+ def describe_node?(node)
32
+ node.name == :describe
33
+ end
34
+
35
+ def context_node?(node)
36
+ node.name == :context
37
+ end
38
+
39
+ def example_node?(node)
40
+ node.name == :it || node.name == :specify || node.name == :example
41
+ end
42
+
43
+ def handle_root_describe_node(node)
44
+ @root.title = node.arguments.arguments.first.name
45
+ call_nodes_in_block(node).each do |child_node|
46
+ if describe_node?(child_node)
47
+ @root.descriptions << RspecTree::Description.new
48
+ handle_describe_node(child_node, @root.descriptions.last)
49
+ end
50
+ end
51
+ end
52
+
53
+ def handle_describe_node(node, parent)
54
+ parent.title = node.arguments.arguments.first.unescaped
55
+ call_nodes_in_block(node).each do |child_node|
56
+ if context_node?(child_node)
57
+ parent.contexts << RspecTree::Context.new
58
+ handle_context_node(child_node, parent.contexts.last)
59
+ end
60
+ end
61
+ end
62
+
63
+ def handle_context_node(node, parent)
64
+ parent.title = node.arguments.arguments.first.unescaped
65
+ call_nodes_in_block(node).each do |child_node|
66
+ if context_node?(child_node)
67
+ parent.contexts << RspecTree::Context.new
68
+ handle_context_node(child_node, parent.contexts.last)
69
+ elsif example_node?(child_node)
70
+ parent.examples << RspecTree::Example.new
71
+ handle_example_node(child_node, parent.examples.last)
72
+ end
73
+ end
74
+ end
75
+
76
+ def handle_example_node(node, parent)
77
+ parent.title = node.arguments.arguments.first.unescaped
78
+ end
79
+
80
+ def call_nodes_in_block(node)
81
+ call_nodes = []
82
+ node.compact_child_nodes.each do |child_node|
83
+ next unless block_node?(child_node)
84
+
85
+ call_nodes = child_node.compact_child_nodes.first.compact_child_nodes.select do |grand_child_node|
86
+ call_node?(grand_child_node)
87
+ end
88
+ end
89
+ call_nodes
90
+ end
91
+
92
+ def visit_call_node(node)
93
+ if root_describe_node?(node)
94
+ handle_root_describe_node(node)
95
+ elsif describe_node?(node)
96
+ handle_describe_node(node)
97
+ elsif context_node?(node)
98
+ handle_context_node(node)
99
+ elsif example_node?(node)
100
+ handle_example_node(node)
101
+ end
102
+ end
103
+ end
104
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sasamuku
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-25 00:00:00.000000000 Z
11
+ date: 2024-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -34,6 +34,7 @@ extra_rdoc_files: []
34
34
  files:
35
35
  - ".rspec"
36
36
  - ".rubocop.yml"
37
+ - ".ruby-version"
37
38
  - CHANGELOG.md
38
39
  - CODE_OF_CONDUCT.md
39
40
  - Gemfile
@@ -44,11 +45,13 @@ files:
44
45
  - exe/rspec_tree
45
46
  - lib/rspec_tree.rb
46
47
  - lib/rspec_tree/cli.rb
48
+ - lib/rspec_tree/context.rb
49
+ - lib/rspec_tree/description.rb
50
+ - lib/rspec_tree/example.rb
51
+ - lib/rspec_tree/root.rb
47
52
  - lib/rspec_tree/tree.rb
48
- - lib/rspec_tree/tree/monkey_patch.rb
49
- - lib/rspec_tree/tree/rspec.rb
50
53
  - lib/rspec_tree/version.rb
51
- - rspec_tree.gemspec
54
+ - lib/rspec_tree/visitor.rb
52
55
  - sig/rspec_tree.rbs
53
56
  homepage: https://github.com/sasamuku/rspec_tree
54
57
  licenses:
@@ -65,14 +68,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
65
68
  requirements:
66
69
  - - ">="
67
70
  - !ruby/object:Gem::Version
68
- version: 2.6.0
71
+ version: 3.3.1
69
72
  required_rubygems_version: !ruby/object:Gem::Requirement
70
73
  requirements:
71
74
  - - ">="
72
75
  - !ruby/object:Gem::Version
73
76
  version: '0'
74
77
  requirements: []
75
- rubygems_version: 3.5.6
78
+ rubygems_version: 3.5.9
76
79
  signing_key:
77
80
  specification_version: 4
78
81
  summary: tree command for rspec test files.
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RspecTree
4
- # This is a monkey patch to override basic behavior
5
- class Tree
6
- Class.class_eval do
7
- def const_missing(name)
8
- name.to_s
9
- end
10
- end
11
-
12
- private
13
-
14
- def require_relative(file); end
15
-
16
- def require(file); end
17
-
18
- def include(*args); end
19
-
20
- def method_missing(method, *args, &block); end
21
-
22
- def respond_to_missing?(method, *)
23
- super
24
- end
25
- end
26
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RspecTree
4
- class Tree
5
- # This module is used to override the RSpec module
6
- module RSpec
7
- class << self
8
- def describe(*args, &block)
9
- puts "desc: #{args.first}"
10
- block.call
11
- end
12
- end
13
- end
14
- end
15
- end
data/rspec_tree.gemspec DELETED
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/rspec_tree/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "rspec_tree"
7
- spec.version = RspecTree::VERSION
8
- spec.authors = ["sasamuku"]
9
- spec.email = ["sasazawa3330@gmail.com"]
10
-
11
- spec.summary = "tree command for rspec test files."
12
- spec.description = "tree command for rspec test files."
13
- spec.homepage = "https://github.com/sasamuku/rspec_tree"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.6.0"
16
-
17
- # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
-
19
- spec.metadata["homepage_uri"] = spec.homepage
20
- spec.metadata["source_code_uri"] = "https://github.com/sasamuku/rspec_tree"
21
- spec.metadata["changelog_uri"] = "https://github.com/sasamuku/rspec_tree"
22
-
23
- # Specify which files should be added to the gem when it is released.
24
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
- spec.files = Dir.chdir(__dir__) do
26
- `git ls-files -z`.split("\x0").reject do |f|
27
- (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
28
- end
29
- end
30
- spec.bindir = "exe"
31
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
- spec.require_paths = ["lib"]
33
-
34
- # Uncomment to register a new dependency of your gem
35
- # spec.add_dependency "example-gem", "~> 1.0"
36
-
37
- # For more information and examples about making a new gem, check out our
38
- # guide at: https://bundler.io/guides/creating_gem.html
39
-
40
- spec.add_dependency "thor"
41
- end