proc_to_ast 0.0.7 → 0.2.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
- SHA1:
3
- metadata.gz: 925e6d8267b75283f13ded71a1f3b17c747a0e6a
4
- data.tar.gz: d9d509c4e5e5ab3024d77ced8016e4a34c00aa7b
2
+ SHA256:
3
+ metadata.gz: 2f78e79219512a1b4ad81f78c1569f906701ceaca046bb8d3dadad4886fd80de
4
+ data.tar.gz: a81e8a47f87efd33d6d3ab3e764832621613a0b9e3ed2ffff187f2c476594409
5
5
  SHA512:
6
- metadata.gz: fb81eb0cdeae93b38caa1e77751aceba8804d09e4f5866e7507b0cfad3dbbb8f2eb190a33abfc0e2c5461e91ee11cc2828e7dd69666be00b17d040cc7c3466e5
7
- data.tar.gz: 3e7be1ee19e6497959c8244437547587b18b2665456fdbbaf087c59d359c32a80ccf23dfde1e21400432a1a94fda6f2136a662a968a2304204cdced0cd55ccf3
6
+ metadata.gz: e6e3adeabd531b4cbe84daef769756f68c35480f25a186d50e0cb57856a5616f9bf74cd457a6d58278596425a2b01ad6c3d542dd2baf136ba59c0e50e35b6f44
7
+ data.tar.gz: 6ff7c319838d4d501b02be15fa05dc7ae4a12d31433b28cca76dde54093cb0938b3753523c914e396421cac771f9284034330b506e7022d828c9bc7f8b7e605a
@@ -0,0 +1,27 @@
1
+ name: RSpec
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version: ['3.1', '3.2', '3.3']
15
+
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+ - name: Set up Ruby
19
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
20
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
21
+ # uses: ruby/setup-ruby@v1
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby-version }}
25
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
26
+ - name: Run tests
27
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -20,3 +20,5 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+
24
+ rspec.output
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # proc_to_ast
2
2
  [![Gem Version](https://badge.fury.io/rb/proc_to_ast.svg)](http://badge.fury.io/rb/proc_to_ast)
3
- [![Build Status](https://travis-ci.org/joker1007/proc_to_ast.svg?branch=master)](https://travis-ci.org/joker1007/proc_to_ast)
3
+ [![RSpec](https://github.com/joker1007/proc_to_ast/actions/workflows/rspec.yml/badge.svg)](https://github.com/joker1007/proc_to_ast/actions/workflows/rspec.yml)
4
4
 
5
5
  Add `#to_ast` method to Proc.
6
6
 
@@ -0,0 +1,119 @@
1
+ require "proc_to_ast/version"
2
+
3
+ require "parser/current"
4
+ require "unparser"
5
+ require "rouge"
6
+
7
+ module ProcToAst
8
+ class MultiMatchError < StandardError; end
9
+
10
+ class Parser
11
+ attr_reader :parser
12
+
13
+ @formatter = Rouge::Formatters::Terminal256.new
14
+ @lexer = Rouge::Lexers::Ruby.new
15
+
16
+ class << self
17
+ def highlight(source)
18
+ @formatter.format(@lexer.lex(source))
19
+ end
20
+ end
21
+
22
+ def initialize
23
+ @parser = ::Parser::CurrentRuby.default_parser
24
+ @parser.diagnostics.consumer = ->(diagnostic) {} # suppress error message
25
+ end
26
+
27
+ # Read file and try parsing
28
+ # if success parse, find proc AST
29
+ #
30
+ # @param filename [String] reading file path
31
+ # @param linenum [Integer] start line number
32
+ # @return [Parser::AST::Node] Proc AST
33
+ def parse(filename, linenum)
34
+ @filename, @linenum = filename, linenum
35
+ buf = []
36
+ File.open(filename, "rb").each_with_index do |line, index|
37
+ next if index < linenum - 1
38
+ buf << line
39
+ begin
40
+ return do_parse(buf.join)
41
+ rescue ::Parser::SyntaxError
42
+ node = trim_and_retry(buf)
43
+ return node if node
44
+ end
45
+ end
46
+ fail(::Parser::SyntaxError, "Unknown error")
47
+ end
48
+
49
+ private
50
+
51
+ def do_parse(source)
52
+ parser.reset
53
+
54
+ source_buffer = ::Parser::Source::Buffer.new(@filename, @linenum)
55
+ source_buffer.source = source
56
+ node = parser.parse(source_buffer)
57
+ block_nodes = traverse_node(node)
58
+
59
+ if block_nodes.length == 1
60
+ block_nodes.first
61
+ else
62
+ raise ProcToAst::MultiMatchError
63
+ end
64
+ end
65
+
66
+ # Remove tail comma and wrap dummy method, and retry parsing
67
+ # For proc inner Array or Hash
68
+ def trim_and_retry(buf)
69
+ *lines, last = buf
70
+
71
+ # For inner Array or Hash or Arguments list.
72
+ lines << last.gsub(/,\s*$/, "")
73
+ do_parse("a(#{lines.join})") # wrap dummy method
74
+ rescue ::Parser::SyntaxError
75
+ end
76
+
77
+ def traverse_node(node)
78
+ if node.type != :block
79
+ node.children.flat_map { |child|
80
+ if child.is_a?(AST::Node)
81
+ traverse_node(child)
82
+ end
83
+ }.compact
84
+ else
85
+ [node]
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ class Proc
92
+ # @return [Parser::AST::Node] Proc AST
93
+ def to_ast
94
+ filename, linenum = source_location
95
+ parser = ProcToAst::Parser.new
96
+ parser.parse(filename, linenum)
97
+ end
98
+
99
+ # @param highlight [Boolean] enable output highlight
100
+ # @return [String] proc source code
101
+ def to_source(highlight: false)
102
+ source = Unparser.unparse(to_ast)
103
+ if highlight
104
+ ProcToAst::Parser.highlight(source)
105
+ else
106
+ source
107
+ end
108
+ end
109
+
110
+ def to_raw_source(highlight: false)
111
+ source = to_ast.loc.expression.source.force_encoding("UTF-8")
112
+
113
+ if highlight
114
+ ProcToAst::Parser.highlight(source)
115
+ else
116
+ source
117
+ end
118
+ end
119
+ end
@@ -1,3 +1,3 @@
1
1
  module ProcToAst
2
- VERSION = "0.0.7"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/proc_to_ast.rb CHANGED
@@ -1,122 +1 @@
1
- require "proc_to_ast/version"
2
-
3
- require 'parser/current'
4
- require 'unparser'
5
- require 'coderay'
6
-
7
- module ProcToAst
8
- class MultiMatchError < StandardError; end
9
-
10
- class Parser
11
- attr_reader :parser
12
-
13
- def initialize
14
- @parser = ::Parser::CurrentRuby.default_parser
15
- @parser.diagnostics.consumer = ->(diagnostic) {} # suppress error message
16
- end
17
-
18
- # Read file and try parsing
19
- # if success parse, find proc AST
20
- #
21
- # @param filename [String] reading file path
22
- # @param linenum [Integer] start line number
23
- # @param retry_limit [Integer]
24
- # @return [Parser::AST::Node] Proc AST
25
- def parse(filename, linenum, retry_limit = 20)
26
- @filename, @linenum = filename, linenum
27
- file = File.open(filename, "rb")
28
-
29
- (linenum - 1).times { file.gets }
30
- buf = []
31
- try_count = 0
32
-
33
- begin
34
- try_count += 1
35
-
36
- buf << file.gets
37
- do_parse(buf.join)
38
- rescue ::Parser::SyntaxError => e
39
- node = trim_and_retry(buf)
40
-
41
- return node unless node.nil?
42
- retry if try_count < retry_limit
43
-
44
- raise e
45
- ensure
46
- file.close
47
- end
48
- end
49
-
50
- private
51
-
52
- def do_parse(source)
53
- parser.reset
54
-
55
- source_buffer = ::Parser::Source::Buffer.new(@filename, @linenum)
56
- source_buffer.source = source
57
- node = parser.parse(source_buffer)
58
- block_nodes = traverse_node(node)
59
-
60
- if block_nodes.length == 1
61
- block_nodes.first
62
- else
63
- raise ProcToAst::MultiMatchError
64
- end
65
- end
66
-
67
- # Remove tail comma and wrap dummy method, and retry parsing
68
- # For proc inner Array or Hash
69
- def trim_and_retry(buf)
70
- *lines, last = buf
71
-
72
- # For inner Array or Hash or Arguments list.
73
- lines << last.gsub(/,\s*$/, "")
74
- do_parse("a(#{lines.join})") # wrap dummy method
75
- rescue ::Parser::SyntaxError
76
- end
77
-
78
- def traverse_node(node)
79
- if node.type != :block
80
- node.children.flat_map { |child|
81
- if child.is_a?(AST::Node)
82
- traverse_node(child)
83
- end
84
- }.compact
85
- else
86
- [node]
87
- end
88
- end
89
- end
90
- end
91
-
92
- class Proc
93
- # @param retry_limit [Integer]
94
- # @return [Parser::AST::Node] Proc AST
95
- def to_ast(retry_limit = 20)
96
- filename, linenum = source_location
97
- parser = ProcToAst::Parser.new
98
- parser.parse(filename, linenum, retry_limit)
99
- end
100
-
101
- # @param highlight [Boolean] enable output highlight
102
- # @param retry_limit [Integer]
103
- # @return [String] proc source code
104
- def to_source(highlight: false, retry_limit: 20)
105
- source = Unparser.unparse(to_ast(retry_limit))
106
- if highlight
107
- CodeRay.scan(source, :ruby).terminal
108
- else
109
- source
110
- end
111
- end
112
-
113
- def to_raw_source(highlight: false, retry_limit: 20)
114
- source = to_ast(retry_limit).loc.expression.source
115
-
116
- if highlight
117
- CodeRay.scan(source, :ruby).terminal
118
- else
119
- source
120
- end
121
- end
122
- end
1
+ require "proc_to_ast/parser_gem"
data/proc_to_ast.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency "parser"
22
22
  spec.add_runtime_dependency "unparser"
23
- spec.add_runtime_dependency "coderay"
23
+ spec.add_runtime_dependency "rouge"
24
24
 
25
25
  spec.add_development_dependency "bundler", ">= 1.5"
26
26
  spec.add_development_dependency "rake"
@@ -23,6 +23,32 @@ describe Proc do
23
23
  expect(pr.to_ast).to be_a(AST::Node)
24
24
  end
25
25
 
26
+ it "long proc" do
27
+ pr = Proc.new do |b|
28
+ p 1
29
+ p 1
30
+ p 1
31
+ p 1
32
+ p 1
33
+ p 1
34
+ p 1
35
+ p 1
36
+ p 1
37
+ p 1
38
+ p 1
39
+ p 1
40
+ p 1
41
+ p 1
42
+ p 1
43
+ p 1
44
+ p 1
45
+ p 1
46
+ p 1
47
+ end
48
+
49
+ expect(pr.to_ast).to be_a(AST::Node)
50
+ end
51
+
26
52
  it "converts block passing method" do
27
53
  def receive_block(&block)
28
54
  block.to_ast
@@ -65,9 +91,9 @@ describe Proc do
65
91
  end
66
92
  ]
67
93
  expect(array[1].to_ast).to be_a(AST::Node)
68
- expect(array[1].to_source).to eq("lambda do\n 2\nend")
69
- expect(array[2][0].to_source).to eq("lambda do\n 3\nend")
70
- expect(array[3].to_source).to eq("proc do |a|\n [a]\nend")
94
+ expect(array[1].to_source).to eq("lambda {\n 2\n}")
95
+ expect(array[2][0].to_source).to eq("lambda {\n 3\n}")
96
+ expect(array[3].to_source).to eq("proc { |a,|\n [a]\n}")
71
97
  end
72
98
 
73
99
  it "inner two dimension array" do
@@ -82,7 +108,7 @@ describe Proc do
82
108
  it "inner hash" do
83
109
  hash_oneline = {a: -> { 1 }}
84
110
  expect(hash_oneline[:a].to_ast).to be_a(AST::Node)
85
- expect(hash_oneline[:a].to_source).to eq("lambda do\n 1\nend")
111
+ expect(hash_oneline[:a].to_source).to eq("lambda {\n 1\n}")
86
112
  end
87
113
 
88
114
  it "inner multiline hash" do
@@ -95,13 +121,13 @@ describe Proc do
95
121
  d: -> { 4 }
96
122
  }
97
123
  expect(hash[:a].to_ast).to be_a(AST::Node)
98
- expect(hash[:a].to_source).to eq("lambda do\n 1\nend")
124
+ expect(hash[:a].to_source).to eq("lambda {\n 1\n}")
99
125
  expect(hash[:b].to_ast).to be_a(AST::Node)
100
- expect(hash[:b].to_source).to eq("lambda do\n 2\nend")
126
+ expect(hash[:b].to_source).to eq("lambda {\n 2\n}")
101
127
  expect(hash[:c].to_ast).to be_a(AST::Node)
102
- expect(hash[:c].to_source).to eq("lambda do\n 3\nend")
128
+ expect(hash[:c].to_source).to eq("lambda {\n 3\n}")
103
129
  expect(hash[:d].to_ast).to be_a(AST::Node)
104
- expect(hash[:d].to_source).to eq("lambda do\n 4\nend")
130
+ expect(hash[:d].to_source).to eq("lambda {\n 4\n}")
105
131
  end
106
132
 
107
133
  it "inner another hash" do
@@ -110,7 +136,7 @@ describe Proc do
110
136
  }
111
137
 
112
138
  expect(hash[:b].to_ast).to be_a(AST::Node)
113
- expect(hash[:b].to_source).to eq("lambda do\n 2\nend")
139
+ expect(hash[:b].to_source).to eq("lambda {\n 2\n}")
114
140
  end
115
141
  end
116
142
  end
@@ -121,8 +147,20 @@ describe Proc do
121
147
  p a
122
148
  }
123
149
 
124
- expect(fuga.to_source).to eq("lambda do |a|\n p(a)\nend")
125
- expect(fuga.to_source(highlight: true)).to eq("lambda \e[32mdo\e[0m |a|\n p(a)\n\e[32mend\e[0m")
150
+ expect(fuga.to_source).to eq("lambda { |a,|\n p(a)\n}")
151
+ expect(fuga.to_source(highlight: true)).to eq("\e[01mlambda\e[00m\e[38;5;230m \e[39m\e[38;5;87m{\e[39m\e[38;5;230m \e[39m\e[38;5;87;01m|\e[39;00m\e[38;5;230ma\e[39m\e[38;5;87m,\e[39m\e[38;5;87;01m|\e[39;00m\e[38;5;230m\e[39m\n\e[38;5;230m \e[39m\e[01mp\e[00m\e[38;5;87m(\e[39m\e[38;5;230ma\e[39m\e[38;5;87m)\e[39m\e[38;5;230m\e[39m\n\e[38;5;230m\e[39m\e[38;5;87m}\e[39m")
152
+ end
153
+
154
+ it "charset is UTF-8" do
155
+ fuga = ->(a) {
156
+ p a
157
+ }
158
+ expect(fuga.to_source.encoding).to eq(Encoding::UTF_8)
159
+ end
160
+
161
+ it "can handle multibyte characters" do
162
+ pr = ->(a) { a + "ほげほげ" }
163
+ expect(pr.to_source).to eq("lambda { |a,|\n a + \"\\xE3\\x81\\xBB\\xE3\\x81\\x92\\xE3\\x81\\xBB\\xE3\\x81\\x92\"\n}")
126
164
  end
127
165
  end
128
166
 
@@ -132,5 +170,16 @@ describe Proc do
132
170
 
133
171
  expect(pr.to_raw_source).to eq("->(a) { a + 1 }")
134
172
  end
173
+
174
+ it "charset is UTF-8" do
175
+ pr = ->(a) { a + 1 }
176
+ expect(pr.to_raw_source.encoding).to eq(Encoding::UTF_8)
177
+ end
178
+
179
+ it "can handle multibyte characters" do
180
+ pr = ->(a) { a + "ほげほげ" }
181
+ expect(pr.to_raw_source).to eq("->(a) { a + \"ほげほげ\" }")
182
+ expect(pr.to_raw_source(highlight: true)).to eq("\e[38;5;87;01m->\e[39;00m\e[38;5;87m(\e[39m\e[38;5;230ma\e[39m\e[38;5;87m)\e[39m\e[38;5;230m \e[39m\e[38;5;87m{\e[39m\e[38;5;230m \e[39m\e[38;5;230ma\e[39m\e[38;5;230m \e[39m\e[38;5;87;01m+\e[39;00m\e[38;5;230m \e[39m\e[38;5;229;01m\"ほげほげ\"\e[39;00m\e[38;5;230m \e[39m\e[38;5;87m}\e[39m")
183
+ end
135
184
  end
136
185
  end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require 'proc_to_ast'
2
+ require 'proc_to_ast/parser_gem'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proc_to_ast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joker1007
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-01 00:00:00.000000000 Z
11
+ date: 2024-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: coderay
42
+ name: rouge
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -101,14 +101,15 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - ".github/workflows/rspec.yml"
104
105
  - ".gitignore"
105
106
  - ".rspec"
106
- - ".travis.yml"
107
107
  - Gemfile
108
108
  - LICENSE.txt
109
109
  - README.md
110
110
  - Rakefile
111
111
  - lib/proc_to_ast.rb
112
+ - lib/proc_to_ast/parser_gem.rb
112
113
  - lib/proc_to_ast/version.rb
113
114
  - proc_to_ast.gemspec
114
115
  - spec/proc_to_ast_spec.rb
@@ -117,7 +118,7 @@ homepage: https://github.com/joker1007/proc_to_ast
117
118
  licenses:
118
119
  - MIT
119
120
  metadata: {}
120
- post_install_message:
121
+ post_install_message:
121
122
  rdoc_options: []
122
123
  require_paths:
123
124
  - lib
@@ -132,9 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
133
  - !ruby/object:Gem::Version
133
134
  version: '0'
134
135
  requirements: []
135
- rubyforge_project:
136
- rubygems_version: 2.2.2
137
- signing_key:
136
+ rubygems_version: 3.5.3
137
+ signing_key:
138
138
  specification_version: 4
139
139
  summary: Convert Proc object to AST::Node
140
140
  test_files:
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
- rvm:
4
- - 2.1.1
5
- - 2.0.0
6
- notifications:
7
- email:
8
- on_success: change