masamune-ast 1.1.0 → 1.1.2

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: 1ee5dca320a96035fcea4f73effbc3fceff2ee531808bf94d99aa21086186ce5
4
- data.tar.gz: 3f170766c1e97a15e9c550e61fc5f2048b28b48a5f12e2b4841a31b0dad6ebbb
3
+ metadata.gz: 0cafe74abe55158e29178163ef544558f8e8d042d8adae0668a8625e1883c843
4
+ data.tar.gz: f0068f9e6783403ba0d17f65902c0ecfded0806424383c8d325168ce0b4c7a58
5
5
  SHA512:
6
- metadata.gz: 7650eff09ecb23034c236363ee70a971f003736a967f8efd5ae8f36e68d598f73a4239a38d839f478b4aa6b36662d7114834dedf501acfed6bd2adcb6494890e
7
- data.tar.gz: fbd0fc4a505b03dc38304abdfadd9cb31fccf5f746bbb325056c63e9a790d7814bd7292d40c95da7441731cf3ab0613f2e9879c4c27f07f61445370a499665a2
6
+ metadata.gz: b6647c5ea9745d2e1f842a0d0eea3de05e795c7afa9a3241cf9d6a87dd802c4c62e7c9fdb266afcbc8e54ffe51af25d9bacc32830d4f28009f9c34b2a4f733a8
7
+ data.tar.gz: d7781f44d57a0bca23d7a61eaed10cdb687431a66540433ac0e01f43c6a625cd05aea2cd06168b1ea980d2fffaa827634ba3633ca8a94950df2110a60d4f9f5c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- masamune-ast (1.1.0)
4
+ masamune-ast (1.1.2)
5
5
  activesupport
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -13,8 +13,38 @@ Or add the following to your Gemfile and run `bundle install`
13
13
  gem "masamune-ast"
14
14
  ```
15
15
 
16
+ Then require the gem in a file like this:
17
+ ```ruby
18
+ require "masamune"
19
+ ```
20
+
16
21
  ## Usage
17
22
 
23
+ Isolate and replace variables, methods, or strings in your Ruby source code according to the specific tokens allotted when the code is intially parsed:
24
+ ```ruby
25
+ code = <<~CODE
26
+ 10.times do |n|
27
+ puts n
28
+ end
29
+
30
+ def n
31
+ "n"
32
+ end
33
+ CODE
34
+
35
+ msmn = Masamune::AbstractSyntaxTree.new(code)
36
+ msmn.replace(type: :variables, old_token: "n", new_token: "foo")
37
+
38
+ # This will produce the following code in string form.
39
+ 10.times do |foo|
40
+ puts foo
41
+ end
42
+
43
+ def n
44
+ "n"
45
+ end
46
+ ```
47
+
18
48
  Pinpoint variables and methods in your source code even when other tokens have the same or similar spelling:
19
49
  ```ruby
20
50
  code = <<CODE
@@ -14,7 +14,7 @@ module Masamune
14
14
  # nice to find out and implement it document/implement it somewhere.
15
15
  def extract_data_nodes
16
16
  @contents[1][1].map do |content|
17
- Masamune::AbstractSyntaxTree::DataNode.new(content, @ast_id)
17
+ DataNode.new(content, @ast_id)
18
18
  end
19
19
  end
20
20
  end
@@ -11,7 +11,7 @@ module Masamune
11
11
 
12
12
  def params
13
13
  # This node should exist already, so we search for it in the ast object.
14
- block_var = Masamune::AbstractSyntaxTree::BlockVar.new(contents[1], ast_id)
14
+ block_var = BlockVar.new(contents[1], ast_id)
15
15
  ast.node_list.find {|node| node.contents == block_var.contents}
16
16
  end
17
17
  end
@@ -9,7 +9,7 @@ module Masamune
9
9
 
10
10
  def extract_data_nodes
11
11
  [
12
- Masamune::AbstractSyntaxTree::DataNode.new(@contents.last, @ast_id)
12
+ DataNode.new(@contents.last, @ast_id)
13
13
  ]
14
14
  end
15
15
  end
@@ -9,7 +9,7 @@ module Masamune
9
9
 
10
10
  def extract_data_nodes
11
11
  [
12
- Masamune::AbstractSyntaxTree::DataNode.new(@contents[1], @ast_id)
12
+ DataNode.new(@contents[1], @ast_id)
13
13
  ]
14
14
  end
15
15
  end
@@ -11,7 +11,7 @@ module Masamune
11
11
 
12
12
  def params
13
13
  # This node should exist already, so we search for it in the ast object.
14
- block_var = Masamune::AbstractSyntaxTree::BlockVar.new(contents[1], ast_id)
14
+ block_var = BlockVar.new(contents[1], ast_id)
15
15
  ast.node_list.find {|node| node.contents == block_var.contents}
16
16
  end
17
17
  end
@@ -14,7 +14,7 @@ module Masamune
14
14
  # to ensure that it's being handled properly.
15
15
  unless @contents[1].nil?
16
16
  @contents[1].map do |content|
17
- Masamune::AbstractSyntaxTree::DataNode.new(content, @ast_id)
17
+ DataNode.new(content, @ast_id)
18
18
  end
19
19
  end
20
20
  end
@@ -9,7 +9,7 @@ module Masamune
9
9
 
10
10
  def extract_data_nodes
11
11
  [
12
- Masamune::AbstractSyntaxTree::DataNode.new(@contents[1], @ast_id)
12
+ DataNode.new(@contents[1], @ast_id)
13
13
  ]
14
14
  end
15
15
  end
@@ -9,7 +9,7 @@ module Masamune
9
9
 
10
10
  def extract_data_nodes
11
11
  [
12
- Masamune::AbstractSyntaxTree::DataNode.new(@contents[1], @ast_id)
12
+ DataNode.new(@contents[1], @ast_id)
13
13
  ]
14
14
  end
15
15
  end
@@ -11,7 +11,7 @@ module Masamune
11
11
 
12
12
  def extract_data_nodes
13
13
  [
14
- Masamune::AbstractSyntaxTree::DataNode.new(@contents[1], @ast_id)
14
+ DataNode.new(@contents[1], @ast_id)
15
15
  ]
16
16
  end
17
17
  end
@@ -9,7 +9,7 @@ module Masamune
9
9
 
10
10
  def extract_data_nodes
11
11
  [
12
- Masamune::AbstractSyntaxTree::DataNode.new(@contents[1], @ast_id)
12
+ DataNode.new(@contents[1], @ast_id)
13
13
  ]
14
14
  end
15
15
  end
@@ -1,13 +1,14 @@
1
1
  module Masamune
2
2
  class AbstractSyntaxTree
3
- attr_reader :tree
3
+ attr_reader :code, :tree
4
4
  attr_accessor :node_list, :data_node_list, :lex_nodes
5
5
 
6
6
  def initialize(code)
7
+ @code = code
7
8
  @tree = Ripper.sexp(code)
8
9
  raw_lex_nodes = Ripper.lex(code)
9
10
  @lex_nodes = raw_lex_nodes.map do |lex_node|
10
- Masamune::LexNode.new(raw_lex_nodes.index(lex_node), lex_node, self.__id__)
11
+ LexNode.new(raw_lex_nodes.index(lex_node), lex_node, self.__id__)
11
12
  end
12
13
 
13
14
  @node_list = []
@@ -21,7 +22,7 @@ module Masamune
21
22
  msmn_node = klass.new(tree_node, self.__id__)
22
23
  else
23
24
  # Create a general node if the node is a single value.
24
- msmn_node = Masamune::AbstractSyntaxTree::Node.new(tree_node, self.__id__)
25
+ msmn_node = Node.new(tree_node, self.__id__)
25
26
  end
26
27
 
27
28
  # Register nodes and any data nodes housed within it.
@@ -69,6 +70,14 @@ module Masamune
69
70
  def brace_block_params
70
71
  end
71
72
 
73
+ # @tree only shows comments as a type of `:void_stmt` and
74
+ # doesn't have a data node, so we get comments from @lex_nodes.
75
+ def comments(content: nil)
76
+ comments = @lex_nodes.select {|node| node.type == :comment}
77
+ comments.select {|comment| comment.token == content} if content
78
+ comments.map {|comment| {position: comment.position, token: comment.token}}
79
+ end
80
+
72
81
  def all_methods
73
82
  method_definitions + method_calls
74
83
  end
@@ -83,37 +92,48 @@ module Masamune
83
92
  # Ensure the classes are in an array
84
93
  token_classes = [token_classes].flatten
85
94
 
86
- var_nodes = []
95
+ nodes = []
87
96
  token_classes.each do |klass|
88
- var_nodes << @node_list.select {|node| node.class == klass}
97
+ nodes << @node_list.select {|node| node.class == klass}
89
98
  end
90
99
 
91
100
  # Searching for multiple classes will yield multi-dimensional arrays,
92
101
  # so we ensure everything is flattened out before moving forward.
93
- var_nodes.flatten!
102
+ nodes.flatten!
94
103
 
95
104
  if token
96
- var_nodes = var_nodes.select {|node| node.data_nodes.first.token == token}.flatten
105
+ # TODO: This most likely shouldn't be `node.data_nodes.first`.
106
+ # There are probably more data_nodes we need to check depending on the node class.
107
+ nodes = nodes.select {|node| node.data_nodes.first.token == token}.flatten
97
108
  end
98
109
 
99
110
  final_result = []
100
- var_nodes.each do |node|
101
- node.data_nodes.each {|dn| final_result << dn.position_and_token}
111
+ nodes.each do |node|
112
+ node.data_nodes.each {|dn| final_result << dn.position_and_token} if node.data_nodes
102
113
  end
103
114
 
104
- Masamune::AbstractSyntaxTree::DataNode.order_results_by_position(final_result)
115
+ DataNode.order_results_by_position(final_result)
116
+ end
117
+
118
+ def replace(type:, old_token:, new_token:)
119
+ Slasher.replace(
120
+ type: type,
121
+ old_token: old_token,
122
+ new_token: new_token,
123
+ code: @code,
124
+ ast: self
125
+ )
105
126
  end
106
127
 
107
128
  private
108
129
 
109
130
  def get_node_class(type)
110
131
  begin
111
- class_name = "Masamune::AbstractSyntaxTree::#{type.to_s.camelize}"
112
- klass = class_name.constantize
132
+ "Masamune::AbstractSyntaxTree::#{type.to_s.camelize}".constantize
113
133
  rescue NameError
114
134
  # For all other nodes that we haven't covered yet, we just make a general class.
115
135
  # We can worry about adding the classes for other nodes as we go.
116
- msmn_node = Masamune::AbstractSyntaxTree::Node
136
+ Node
117
137
  end
118
138
  end
119
139
  end
@@ -0,0 +1,32 @@
1
+ module Masamune
2
+ module Slasher
3
+ def self.replace(type:, old_token:, new_token:, code:, ast:)
4
+ # `type` can either be a method from the ast like `method_definitions`,
5
+ # or it can be a list of Masamune::AbstractSyntaxTree node classes.
6
+ position_and_token_ary = if type.is_a?(Symbol) && ast.respond_to?(type)
7
+ ast.send(type)
8
+ elsif type.is_a?(Array)
9
+ type.map {|klass| ast.find_nodes(klass)}.flatten
10
+ end
11
+
12
+ tokens_to_replace = position_and_token_ary.select do |pos_and_tok|
13
+ pos_and_tok[:token] == old_token
14
+ end
15
+
16
+ # Build from lex nodes
17
+ result = ast.lex_nodes.map do |lex_node|
18
+ match_found = false
19
+ tokens_to_replace.each do |position_and_token|
20
+ if position_and_token[:position] == lex_node.position
21
+ match_found = true
22
+ break
23
+ end
24
+ end
25
+
26
+ match_found ? new_token : lex_node.token
27
+ end
28
+
29
+ result.join
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Masamune
4
- VERSION = "1.1.0"
4
+ VERSION = "1.1.2"
5
5
  end
data/lib/masamune.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "masamune/version"
4
4
  require "ripper"
5
5
  require "active_support/core_ext/string/inflections"
6
6
  require "masamune/lex_node"
7
+ require "masamune/slasher"
7
8
  require "masamune/abstract_syntax_tree"
8
9
  require "masamune/abstract_syntax_tree/node"
9
10
  require "masamune/abstract_syntax_tree/data_node"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: masamune-ast
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Zayas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-02 00:00:00.000000000 Z
11
+ date: 2023-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -55,7 +55,7 @@ files:
55
55
  - lib/masamune/abstract_syntax_tree/var_ref.rb
56
56
  - lib/masamune/abstract_syntax_tree/vcall.rb
57
57
  - lib/masamune/lex_node.rb
58
- - lib/masamune/slicer.rb
58
+ - lib/masamune/slasher.rb
59
59
  - lib/masamune/version.rb
60
60
  - sig/masamune.rbs
61
61
  homepage: https://www.github.com/gazayas/masamune-ast
@@ -1,19 +0,0 @@
1
- module Masamune
2
- module Slicer
3
- def initialize(ast)
4
- @ast = ast
5
- end
6
-
7
- # TODO
8
-
9
- # def replace(type, token)
10
- # @ast.search(type, token)
11
- # end
12
-
13
- # def insert_inside_block
14
- # end
15
-
16
- # def append_to_block
17
- # end
18
- end
19
- end