proc_to_ast 0.1.0 → 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
- SHA1:
3
- metadata.gz: 5095ab2d916faa3c0fa5d451e7eb2aca7986033c
4
- data.tar.gz: 6e5fb00aabf284d7b201398687ed7d7d85449e4d
2
+ SHA256:
3
+ metadata.gz: 2f78e79219512a1b4ad81f78c1569f906701ceaca046bb8d3dadad4886fd80de
4
+ data.tar.gz: a81e8a47f87efd33d6d3ab3e764832621613a0b9e3ed2ffff187f2c476594409
5
5
  SHA512:
6
- metadata.gz: 5573a429abb1df2000f597e755cca7b1871e4ec3cbb64109286463aed93672f1c2820bbfe40fbfe4eb74a046d78364f2f55a36049f65d2db56af1c474bce6cce
7
- data.tar.gz: e17eaab3f8e06e26b55d77725301a53acfa38622cdaa87e65300923e7b811b85fc39c0d5e6e79b675eaaf2598b33781425f97ce3025b8cb2c5df0d8b3a808708
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.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/proc_to_ast.rb CHANGED
@@ -1,110 +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
- # @return [Parser::AST::Node] Proc AST
24
- def parse(filename, linenum)
25
- @filename, @linenum = filename, linenum
26
- buf = []
27
- File.open(filename, "rb").each_with_index do |line, index|
28
- next if index < linenum - 1
29
- buf << line
30
- begin
31
- return do_parse(buf.join)
32
- rescue ::Parser::SyntaxError
33
- node = trim_and_retry(buf)
34
- return node if node
35
- end
36
- end
37
- fail(::Parser::SyntaxError, 'Unknown error')
38
- end
39
-
40
- private
41
-
42
- def do_parse(source)
43
- parser.reset
44
-
45
- source_buffer = ::Parser::Source::Buffer.new(@filename, @linenum)
46
- source_buffer.source = source
47
- node = parser.parse(source_buffer)
48
- block_nodes = traverse_node(node)
49
-
50
- if block_nodes.length == 1
51
- block_nodes.first
52
- else
53
- raise ProcToAst::MultiMatchError
54
- end
55
- end
56
-
57
- # Remove tail comma and wrap dummy method, and retry parsing
58
- # For proc inner Array or Hash
59
- def trim_and_retry(buf)
60
- *lines, last = buf
61
-
62
- # For inner Array or Hash or Arguments list.
63
- lines << last.gsub(/,\s*$/, "")
64
- do_parse("a(#{lines.join})") # wrap dummy method
65
- rescue ::Parser::SyntaxError
66
- end
67
-
68
- def traverse_node(node)
69
- if node.type != :block
70
- node.children.flat_map { |child|
71
- if child.is_a?(AST::Node)
72
- traverse_node(child)
73
- end
74
- }.compact
75
- else
76
- [node]
77
- end
78
- end
79
- end
80
- end
81
-
82
- class Proc
83
- # @return [Parser::AST::Node] Proc AST
84
- def to_ast
85
- filename, linenum = source_location
86
- parser = ProcToAst::Parser.new
87
- parser.parse(filename, linenum)
88
- end
89
-
90
- # @param highlight [Boolean] enable output highlight
91
- # @return [String] proc source code
92
- def to_source(highlight: false)
93
- source = Unparser.unparse(to_ast)
94
- if highlight
95
- CodeRay.scan(source, :ruby).terminal
96
- else
97
- source
98
- end
99
- end
100
-
101
- def to_raw_source(highlight: false)
102
- source = to_ast.loc.expression.source
103
-
104
- if highlight
105
- CodeRay.scan(source, :ruby).terminal
106
- else
107
- source
108
- end
109
- end
110
- 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"
@@ -91,9 +91,9 @@ describe Proc do
91
91
  end
92
92
  ]
93
93
  expect(array[1].to_ast).to be_a(AST::Node)
94
- expect(array[1].to_source).to eq("lambda do\n 2\nend")
95
- expect(array[2][0].to_source).to eq("lambda do\n 3\nend")
96
- 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}")
97
97
  end
98
98
 
99
99
  it "inner two dimension array" do
@@ -108,7 +108,7 @@ describe Proc do
108
108
  it "inner hash" do
109
109
  hash_oneline = {a: -> { 1 }}
110
110
  expect(hash_oneline[:a].to_ast).to be_a(AST::Node)
111
- 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}")
112
112
  end
113
113
 
114
114
  it "inner multiline hash" do
@@ -121,13 +121,13 @@ describe Proc do
121
121
  d: -> { 4 }
122
122
  }
123
123
  expect(hash[:a].to_ast).to be_a(AST::Node)
124
- expect(hash[:a].to_source).to eq("lambda do\n 1\nend")
124
+ expect(hash[:a].to_source).to eq("lambda {\n 1\n}")
125
125
  expect(hash[:b].to_ast).to be_a(AST::Node)
126
- expect(hash[:b].to_source).to eq("lambda do\n 2\nend")
126
+ expect(hash[:b].to_source).to eq("lambda {\n 2\n}")
127
127
  expect(hash[:c].to_ast).to be_a(AST::Node)
128
- expect(hash[:c].to_source).to eq("lambda do\n 3\nend")
128
+ expect(hash[:c].to_source).to eq("lambda {\n 3\n}")
129
129
  expect(hash[:d].to_ast).to be_a(AST::Node)
130
- expect(hash[:d].to_source).to eq("lambda do\n 4\nend")
130
+ expect(hash[:d].to_source).to eq("lambda {\n 4\n}")
131
131
  end
132
132
 
133
133
  it "inner another hash" do
@@ -136,7 +136,7 @@ describe Proc do
136
136
  }
137
137
 
138
138
  expect(hash[:b].to_ast).to be_a(AST::Node)
139
- expect(hash[:b].to_source).to eq("lambda do\n 2\nend")
139
+ expect(hash[:b].to_source).to eq("lambda {\n 2\n}")
140
140
  end
141
141
  end
142
142
  end
@@ -147,8 +147,20 @@ describe Proc do
147
147
  p a
148
148
  }
149
149
 
150
- expect(fuga.to_source).to eq("lambda do |a|\n p(a)\nend")
151
- 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}")
152
164
  end
153
165
  end
154
166
 
@@ -158,5 +170,16 @@ describe Proc do
158
170
 
159
171
  expect(pr.to_raw_source).to eq("->(a) { a + 1 }")
160
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
161
184
  end
162
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.1.0
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: 2015-05-21 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.4.6
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,9 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.2.2
5
- - 2.1
6
- - 2.0
7
- notifications:
8
- email:
9
- on_success: change