node_visitor 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a596ef648c5a209a47fa0355a8956a14df436f9b82d178560323809387a235aa
4
+ data.tar.gz: 98d3fe4e938c5d841c9d1e34c037cdfa1f1c209cf521c005f732d07cefc8da65
5
+ SHA512:
6
+ metadata.gz: beb38d152e58c83c48c7a1d714b4ba635e6ce226e804d04e00b38568afc6b10f6f4a82e9074ac1e998d30ebd0ff2cdcb271c09748cdb2e3993a132d3e9f4ab06
7
+ data.tar.gz: 5ad89b6ee986b7ac6a7d4ff7834905633a5302018a2e23de16769dab74bd3798ac4ace624f6c5641db3f2ef26de833914b710ca7bc744f7ddb65255c01460732
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.0.0 (2024-04-27)
4
+
5
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in node_visitor.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "rspec", "~> 3.0"
10
+ gem 'parser_node_ext'
11
+ gem 'prism_ext'
12
+ gem 'syntax_tree_ext'
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ node_visitor (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ diff-lcs (1.5.1)
11
+ parser (3.3.0.5)
12
+ ast (~> 2.4.1)
13
+ racc
14
+ parser_node_ext (1.3.2)
15
+ parser
16
+ prettier_print (1.2.1)
17
+ prism (0.27.0)
18
+ prism_ext (0.3.2)
19
+ prism
20
+ racc (1.7.3)
21
+ rake (13.2.1)
22
+ rspec (3.13.0)
23
+ rspec-core (~> 3.13.0)
24
+ rspec-expectations (~> 3.13.0)
25
+ rspec-mocks (~> 3.13.0)
26
+ rspec-core (3.13.0)
27
+ rspec-support (~> 3.13.0)
28
+ rspec-expectations (3.13.0)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.13.0)
31
+ rspec-mocks (3.13.0)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.13.0)
34
+ rspec-support (3.13.1)
35
+ syntax_tree (6.2.0)
36
+ prettier_print (>= 1.2.0)
37
+ syntax_tree_ext (0.8.2)
38
+ syntax_tree
39
+
40
+ PLATFORMS
41
+ ruby
42
+ x86_64-darwin-23
43
+
44
+ DEPENDENCIES
45
+ node_visitor!
46
+ parser_node_ext
47
+ prism_ext
48
+ rake (~> 13.0)
49
+ rspec (~> 3.0)
50
+ syntax_tree_ext
51
+
52
+ BUNDLED WITH
53
+ 2.3.7
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # NodeVisitor
2
+
3
+ [![Build Status](https://github.com/synvert-hq/node-visitor-ruby/actions/workflows/main.yml/badge.svg)](https://github.com/synvert-hq/node-visitor-ruby/actions/workflows/main.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/node_visitor.svg)](https://rubygems.org/gems/node_visitor)
5
+
6
+ NodeVisitor allows you to define callbacks based on node type, then visit the AST nodes.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'node_visitor'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install node_visitor
23
+
24
+ ## Usage
25
+
26
+ 1. initialize the visitor
27
+
28
+ ```ruby
29
+ visitor = NodeVisitor.new(adapter: 'prism')
30
+ ```
31
+
32
+ 2. add callbacks
33
+
34
+ ```ruby
35
+ # this will be triggered when it starts to visit class_node
36
+ visitor.add_callback(:class_node, at: 'start') do |node|
37
+ node.name # get the name of class node
38
+ end
39
+
40
+ # this will be triggered after it finishes to visit class_node
41
+ visitor.add_callback(:class_node, at: 'end') do |node|
42
+ node.name # get the name of class node
43
+ end
44
+ ```
45
+
46
+ There is a special node type, `:all`, which is triggered before or after visiting all nodes.
47
+
48
+ ```ruby
49
+ # this will be triggered after it finishes to visit all nodes
50
+ visitor.add_callback(:class_node, at: 'end') do
51
+ end
52
+ ```
53
+
54
+ 3. visit the AST node
55
+
56
+ ```ruby
57
+ visitor.visit(node)
58
+ ```
59
+
60
+ ## Development
61
+
62
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
63
+
64
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
65
+
66
+ ## Contributing
67
+
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/synvert-hq/node_visitor.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser'
4
+ require 'parser_node_ext'
5
+
6
+ class NodeVisitor::ParserAdapter
7
+ def is_node?(node)
8
+ node.is_a?(Parser::AST::Node)
9
+ end
10
+
11
+ def get_node_type(node)
12
+ node.type
13
+ end
14
+
15
+ def get_children(node)
16
+ node.children
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'prism'
4
+ require 'prism_ext'
5
+
6
+ class NodeVisitor::PrismAdapter
7
+ def is_node?(node)
8
+ node.is_a?(Prism::Node)
9
+ end
10
+
11
+ def get_node_type(node)
12
+ node.type
13
+ end
14
+
15
+ def get_children(node)
16
+ keys = []
17
+ children = []
18
+ node.deconstruct_keys([]).each do |key, value|
19
+ next if [:flags, :location].include?(key)
20
+
21
+ if key.to_s.end_with?('_loc')
22
+ new_key = key.to_s[0..-5]
23
+ unless keys.include?(new_key)
24
+ keys << new_key
25
+ children << node.send(new_key)
26
+ end
27
+ else
28
+ unless keys.include?(key.to_s)
29
+ keys << key.to_s
30
+ children << value
31
+ end
32
+ end
33
+ end
34
+ children
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'syntax_tree'
4
+ require 'syntax_tree_ext'
5
+
6
+ class NodeVisitor::SyntaxTreeAdapter
7
+ def is_node?(node)
8
+ node.is_a?(SyntaxTree::Node)
9
+ end
10
+
11
+ def get_node_type(node)
12
+ node.class.name.split('::').last.to_sym
13
+ end
14
+
15
+ def get_children(node)
16
+ node.deconstruct_keys([]).filter { |key, _value| ![:location, :comments].include?(key) }
17
+ .values
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Abstract Adapter class
4
+ class NodeVisitor::Adapter
5
+ # Check if it is a node
6
+ # @return [Boolean]
7
+ def is_node?(node)
8
+ raise NotImplementedError, 'get_node_type is not implemented'
9
+ end
10
+
11
+ # Get the type of node
12
+ # @param node [Node] ast node
13
+ # @return [Symbol] node type
14
+ def get_node_type(node)
15
+ raise NotImplementedError, 'get_node_type is not implemented'
16
+ end
17
+
18
+ # Get the children of node
19
+ # @param node [Node] ast node
20
+ # @return [Array<Node>] node children
21
+ def get_children(node)
22
+ raise NotImplementedError, 'get_children is not implemented'
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ class NodeVisitor
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,55 @@
1
+ require_relative "node_visitor/version"
2
+
3
+ class NodeVisitor
4
+ class InvalidAdapterError < StandardError; end
5
+
6
+ autoload :Adapter, "node_visitor/adapter"
7
+ autoload :ParserAdapter, "node_visitor/adapter/parser"
8
+ autoload :PrismAdapter, "node_visitor/adapter/prism"
9
+ autoload :SyntaxTreeAdapter, "node_visitor/adapter/syntax_tree"
10
+
11
+ def initialize(adapter:)
12
+ @adapter = get_adapter_instance(adapter)
13
+ @callbacks = {}
14
+ end
15
+
16
+ def add_callback(node_type, at:, &block)
17
+ @callbacks[node_type] ||= []
18
+ @callbacks[node_type] << { block: block, at: at }
19
+ end
20
+
21
+ def visit(node, block_context = self)
22
+ callbacks = @callbacks[:all]
23
+ callbacks.each { |callback| block_context.instance_exec(node, &callback[:block]) if callback[:at] == 'start' } if callbacks
24
+ visit_node(node)
25
+ callbacks.each { |callback| block_context.instance_exec(node, &callback[:block]) if callback[:at] == 'end' } if callbacks
26
+ end
27
+
28
+ private
29
+
30
+ def get_adapter_instance(adapter)
31
+ case adapter.to_sym
32
+ when :parser
33
+ ParserAdapter.new
34
+ when :syntax_tree
35
+ SyntaxTreeAdapter.new
36
+ when :prism
37
+ PrismAdapter.new
38
+ else
39
+ raise InvalidAdapterError, "adapter #{adapter} is not supported"
40
+ end
41
+ end
42
+
43
+ def visit_node(node)
44
+ if node.is_a?(Array)
45
+ node.each { |child_node| visit_node(child_node) }
46
+ return
47
+ end
48
+ return unless @adapter.is_node?(node)
49
+
50
+ callbacks = @callbacks[@adapter.get_node_type(node)]
51
+ callbacks.each { |callback| instance_exec(node, &callback[:block]) if callback[:at] == 'start' } if callbacks
52
+ @adapter.get_children(node).each { |child_node| visit_node(child_node) }
53
+ callbacks.each { |callback| instance_exec(node, &callback[:block]) if callback[:at] == 'end' } if callbacks
54
+ end
55
+ end
@@ -0,0 +1,32 @@
1
+
2
+ require_relative "lib/node_visitor/version"
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "node_visitor"
6
+ spec.version = NodeVisitor::VERSION
7
+ spec.authors = ["Richard Huang"]
8
+ spec.email = ["flyerhzm@gmail.com"]
9
+
10
+ spec.summary = "visit ast nodes"
11
+ spec.description = "visit ast nodes"
12
+ spec.homepage = "https://github.com/synvert-hq/node-visitor-ruby"
13
+ spec.required_ruby_version = ">= 2.6.0"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/synvert-hq/node-visitor-ruby"
17
+ spec.metadata["changelog_uri"] = "https://github.com/synvert-hq/node-visitor-ruby/blob/master/CHANGELOG.md"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ # For more information and examples about making a new gem, check out our
31
+ # guide at: https://bundler.io/guides/creating_gem.html
32
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: node_visitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Huang
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-04-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: visit ast nodes
14
+ email:
15
+ - flyerhzm@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rspec"
21
+ - CHANGELOG.md
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - README.md
25
+ - Rakefile
26
+ - lib/node_visitor.rb
27
+ - lib/node_visitor/adapter.rb
28
+ - lib/node_visitor/adapter/parser.rb
29
+ - lib/node_visitor/adapter/prism.rb
30
+ - lib/node_visitor/adapter/syntax_tree.rb
31
+ - lib/node_visitor/version.rb
32
+ - node_visitor.gemspec
33
+ homepage: https://github.com/synvert-hq/node-visitor-ruby
34
+ licenses: []
35
+ metadata:
36
+ homepage_uri: https://github.com/synvert-hq/node-visitor-ruby
37
+ source_code_uri: https://github.com/synvert-hq/node-visitor-ruby
38
+ changelog_uri: https://github.com/synvert-hq/node-visitor-ruby/blob/master/CHANGELOG.md
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.6.0
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.5.9
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: visit ast nodes
58
+ test_files: []