rinline 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/README.md +44 -0
- data/Rakefile +9 -0
- data/benchmark/simple.rb +36 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rinline.rb +22 -0
- data/lib/rinline/ext/ast_ext.rb +181 -0
- data/lib/rinline/ext/iseq_ext.rb +11 -0
- data/lib/rinline/ext/method_ext.rb +40 -0
- data/lib/rinline/location.rb +14 -0
- data/lib/rinline/optimizer.rb +155 -0
- data/lib/rinline/runner.rb +57 -0
- data/lib/rinline/version.rb +3 -0
- data/rinline.gemspec +34 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dc0964e6130a5e6bd8f80a5ada38a861082d5576b012c5557e90c07646942d76
|
4
|
+
data.tar.gz: c3a30e6a0c4c5de9c4e003abc2ace61c17a92cb375296de967ffff58e1acb308
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 115a1a1f849277b1725e6c32555e9a85acc39a18dbcc5d7738a0825c3df0921f788dea8b1e34ccf3337d1add62aafe483c5178bd8c07ad1a4ad794b9b1809864
|
7
|
+
data.tar.gz: 5d00f2b9fccf4811176f91a4e3e96c7a966041c4bf0b4c2d719ee451944d0aa47c7525d035e3b116bd70509e99a3503f21c9cfc56e9b1c7f0a6b40b3cb12ba13
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Rinline
|
2
|
+
|
3
|
+
Inline expansion for Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'rinline'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install rinline
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Call `Rinline.optimize` after your program is loaded, but before your program is not ran yet.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'your_program'
|
27
|
+
require 'rinline'
|
28
|
+
|
29
|
+
Rinline.optimize do |r|
|
30
|
+
r.optimize_namespace(YourProgram)
|
31
|
+
end
|
32
|
+
|
33
|
+
YourProgram.start
|
34
|
+
```
|
35
|
+
|
36
|
+
## Development
|
37
|
+
|
38
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
39
|
+
|
40
|
+
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).
|
41
|
+
|
42
|
+
## Contributing
|
43
|
+
|
44
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pocke/rinline.
|
data/Rakefile
ADDED
data/benchmark/simple.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# $ ruby benchmark/simple.rb
|
2
|
+
# user system total real
|
3
|
+
# plain 6.203292 0.000000 6.203292 ( 6.206694)
|
4
|
+
# optimized 3.623372 0.000000 3.623372 ( 3.625261)
|
5
|
+
|
6
|
+
require 'benchmark'
|
7
|
+
|
8
|
+
class C
|
9
|
+
def plain
|
10
|
+
m + n
|
11
|
+
end
|
12
|
+
|
13
|
+
def optimized
|
14
|
+
m + n
|
15
|
+
end
|
16
|
+
|
17
|
+
def m
|
18
|
+
1
|
19
|
+
end
|
20
|
+
|
21
|
+
def n
|
22
|
+
2
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rinline'
|
27
|
+
Rinline.optimize do |r|
|
28
|
+
r.optimize_instance_method(C, :optimized)
|
29
|
+
end
|
30
|
+
|
31
|
+
i = C.new
|
32
|
+
|
33
|
+
Benchmark.bm(20) do |x|
|
34
|
+
x.report('plain') { 100000000.times { i.plain } }
|
35
|
+
x.report('optimized') { 100000000.times { i.optimized } }
|
36
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rinline"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/rinline.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
require_relative "./rinline/version"
|
4
|
+
require_relative './rinline/ext/iseq_ext'
|
5
|
+
require_relative './rinline/ext/ast_ext'
|
6
|
+
require_relative './rinline/ext/method_ext'
|
7
|
+
require_relative './rinline/optimizer'
|
8
|
+
require_relative './rinline/location'
|
9
|
+
require_relative './rinline/runner'
|
10
|
+
|
11
|
+
module Rinline
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def optimize(&block)
|
15
|
+
runner = Runner.new
|
16
|
+
Runner.current = runner
|
17
|
+
block.call runner
|
18
|
+
Runner.current = nil
|
19
|
+
|
20
|
+
$stderr.puts "[Rinline] Optimizing is finised" if runner.debug
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module Rinline
|
2
|
+
module Ext
|
3
|
+
module AstExt
|
4
|
+
refine RubyVM::AbstractSyntaxTree::Node do
|
5
|
+
def traverse(&block)
|
6
|
+
opt = {}
|
7
|
+
block.call self, opt
|
8
|
+
|
9
|
+
# workaround for modifiers
|
10
|
+
# TODO: Remove this workaround by refining offset
|
11
|
+
if ((type == :IF || type == :UNLESS) && children[2] == nil && children[1].before_than(children[0])) ||
|
12
|
+
((type == :WHILE || type == :UNTIL) && children[1].before_than(children[0]))
|
13
|
+
children[1].traverse(&block)
|
14
|
+
children[0].traverse(&block)
|
15
|
+
else
|
16
|
+
self.children.each.with_index do |child, index|
|
17
|
+
next if opt[:ignore_index] == index
|
18
|
+
child.traverse(&block) if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_source(path)
|
24
|
+
file(path)[first_index(path)..last_index(path)]
|
25
|
+
end
|
26
|
+
|
27
|
+
def location(path)
|
28
|
+
Location.new(first_index(path), last_index(path))
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_child?(*types)
|
32
|
+
traverse do |child|
|
33
|
+
return true if child.is_a?(RubyVM::AbstractSyntaxTree::Node) && types.include?(child.type)
|
34
|
+
end
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
|
38
|
+
# var = 1
|
39
|
+
# ^^^
|
40
|
+
def location_variable_name_of_lasgn(path)
|
41
|
+
type! :LASGN
|
42
|
+
first_index = first_index(path)
|
43
|
+
|
44
|
+
Location.new(first_index, first_index + self.children[0].size - 1)
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_body
|
48
|
+
type! :SCOPE
|
49
|
+
self.children[2]
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_args
|
53
|
+
type! :SCOPE
|
54
|
+
self.children[1]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Extensions for ARGS
|
58
|
+
def args_pre_num
|
59
|
+
type! :ARGS
|
60
|
+
self.children[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
def args_pre_init
|
64
|
+
type! :ARGS
|
65
|
+
self.children[1]
|
66
|
+
end
|
67
|
+
|
68
|
+
def args_opt
|
69
|
+
type! :ARGS
|
70
|
+
self.children[2]
|
71
|
+
end
|
72
|
+
|
73
|
+
def args_first_post
|
74
|
+
type! :ARGS
|
75
|
+
self.children[3]
|
76
|
+
end
|
77
|
+
|
78
|
+
def args_post_num
|
79
|
+
type! :ARGS
|
80
|
+
self.children[4]
|
81
|
+
end
|
82
|
+
|
83
|
+
def args_post_init
|
84
|
+
type! :ARGS
|
85
|
+
self.children[5]
|
86
|
+
end
|
87
|
+
|
88
|
+
def args_rest
|
89
|
+
type! :ARGS
|
90
|
+
self.children[6]
|
91
|
+
end
|
92
|
+
|
93
|
+
def args_kw
|
94
|
+
type! :ARGS
|
95
|
+
self.children[7]
|
96
|
+
end
|
97
|
+
|
98
|
+
def args_kwrest
|
99
|
+
type! :ARGS
|
100
|
+
self.children[8]
|
101
|
+
end
|
102
|
+
|
103
|
+
def args_block
|
104
|
+
type! :ARGS
|
105
|
+
self.children[9]
|
106
|
+
end
|
107
|
+
|
108
|
+
def expandable_method?(parameter_size)
|
109
|
+
a = self.method_args
|
110
|
+
a.args_pre_num == parameter_size &&
|
111
|
+
a.args_pre_init == nil &&
|
112
|
+
a.args_opt == nil &&
|
113
|
+
a.args_first_post == nil &&
|
114
|
+
a.args_post_num == 0 &&
|
115
|
+
a.args_post_init == nil &&
|
116
|
+
a.args_rest == nil &&
|
117
|
+
a.args_kw == nil &&
|
118
|
+
a.args_kwrest == nil &&
|
119
|
+
a.args_block == nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def array_size
|
123
|
+
type! :ARRAY
|
124
|
+
self.children.size - 1
|
125
|
+
end
|
126
|
+
|
127
|
+
def array_content
|
128
|
+
type! :ARRAY
|
129
|
+
self.children[0..-2]
|
130
|
+
end
|
131
|
+
|
132
|
+
def fcall_args
|
133
|
+
type! :FCALL
|
134
|
+
self.children[1]
|
135
|
+
end
|
136
|
+
|
137
|
+
def lasgn_opasgn?
|
138
|
+
type! :LASGN
|
139
|
+
right = children[1]
|
140
|
+
first_lineno == right.first_lineno &&
|
141
|
+
first_column == right.first_column
|
142
|
+
end
|
143
|
+
|
144
|
+
private def first_index(path)
|
145
|
+
return first_column if first_lineno == 1
|
146
|
+
|
147
|
+
lines = file(path).split("\n")
|
148
|
+
lines[0..(first_lineno - 2)].sum(&:size) +
|
149
|
+
first_lineno - 1 + # For \n
|
150
|
+
first_column
|
151
|
+
end
|
152
|
+
|
153
|
+
private def last_index(path)
|
154
|
+
last_column = self.last_column - 1
|
155
|
+
return last_column if last_lineno == 1
|
156
|
+
|
157
|
+
lines = file(path).split("\n")
|
158
|
+
lines[0..(last_lineno - 2)].sum(&:size) +
|
159
|
+
last_lineno - 1 + # For \n
|
160
|
+
last_column
|
161
|
+
end
|
162
|
+
|
163
|
+
private def type!(type)
|
164
|
+
raise "Unexpected type: #{self.type}" unless self.type == type
|
165
|
+
end
|
166
|
+
|
167
|
+
def before_than(right)
|
168
|
+
if self.first_lineno == right.first_lineno
|
169
|
+
self.first_column < right.first_column
|
170
|
+
else
|
171
|
+
self.first_lineno < right.first_lineno
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
private def file(path)
|
176
|
+
Runner.current.file_cache[path] ||= File.binread(path)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Rinline
|
2
|
+
module Ext
|
3
|
+
module MethodExt
|
4
|
+
refine UnboundMethod do
|
5
|
+
using IseqExt
|
6
|
+
using AstExt
|
7
|
+
|
8
|
+
def to_ast
|
9
|
+
RubyVM::AbstractSyntaxTree.of(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_iseq
|
13
|
+
RubyVM::InstructionSequence.of(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def expandable?
|
17
|
+
ruby_method? &&
|
18
|
+
to_iseq&.short? &&
|
19
|
+
!eval? &&
|
20
|
+
!to_ast.has_child?(:SUPER, :ZSUPER, :RETURN, :CONST) &&
|
21
|
+
# HACK: RubyVM::AST omits `return` from tree if it is meaningless.
|
22
|
+
# So checking AST is not enough.
|
23
|
+
!to_ast.to_source(absolute_path).match?(/\breturn\b/)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ruby_method?
|
27
|
+
!!source_location
|
28
|
+
end
|
29
|
+
|
30
|
+
def eval?
|
31
|
+
absolute_path == '(eval)'
|
32
|
+
end
|
33
|
+
|
34
|
+
def absolute_path
|
35
|
+
source_location[0]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Rinline
|
2
|
+
class Optimizer
|
3
|
+
using Ext::MethodExt
|
4
|
+
using Ext::AstExt
|
5
|
+
using Ext::IseqExt
|
6
|
+
|
7
|
+
# @param klass [Class]
|
8
|
+
# @param method_name [Symbol] an instance method name
|
9
|
+
# @return [String,nil] optimized code if optimized
|
10
|
+
def self.optimize(klass, method_name)
|
11
|
+
self.new(klass, method_name).optimize
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(klass, method_name)
|
15
|
+
@klass = klass
|
16
|
+
@method_name = method_name
|
17
|
+
@method = klass.instance_method(method_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def optimize
|
21
|
+
return unless method.ruby_method?
|
22
|
+
return if method.eval?
|
23
|
+
ast = method.to_ast
|
24
|
+
return unless ast
|
25
|
+
return if ast.has_child?(:CONST)
|
26
|
+
path = method.absolute_path
|
27
|
+
replacements = []
|
28
|
+
|
29
|
+
ast.traverse do |node, opt|
|
30
|
+
case node.type
|
31
|
+
when :VCALL
|
32
|
+
target_method_name = node.children[0]
|
33
|
+
next if method_name == target_method_name
|
34
|
+
target_method =
|
35
|
+
begin
|
36
|
+
klass.instance_method(target_method_name)
|
37
|
+
rescue NameError
|
38
|
+
next
|
39
|
+
end
|
40
|
+
next unless target_method.expandable?
|
41
|
+
|
42
|
+
to_ast = target_method.to_ast
|
43
|
+
next unless to_ast.expandable_method?(0)
|
44
|
+
|
45
|
+
to_path = target_method.absolute_path
|
46
|
+
body = to_ast.method_body
|
47
|
+
to_code =
|
48
|
+
if body
|
49
|
+
"((#{replace_lvar(body, to_path)}))"
|
50
|
+
else
|
51
|
+
"()"
|
52
|
+
end
|
53
|
+
replacements << {
|
54
|
+
from: node.location(path),
|
55
|
+
to: to_code,
|
56
|
+
}
|
57
|
+
when :FCALL
|
58
|
+
target_method_name = node.children[0]
|
59
|
+
next if method_name == target_method_name
|
60
|
+
target_method =
|
61
|
+
begin
|
62
|
+
klass.instance_method(target_method_name)
|
63
|
+
rescue NameError
|
64
|
+
next
|
65
|
+
end
|
66
|
+
next unless target_method.expandable?
|
67
|
+
|
68
|
+
to_ast = target_method.to_ast
|
69
|
+
args = node.fcall_args
|
70
|
+
next unless args&.type == :ARRAY
|
71
|
+
next unless to_ast.expandable_method?(args.array_size)
|
72
|
+
|
73
|
+
to_path = target_method.absolute_path
|
74
|
+
lvar_suffix = gen_lvar_suffix
|
75
|
+
|
76
|
+
args = assign_args(to_ast, node, path, lvar_suffix)
|
77
|
+
body =
|
78
|
+
if to_ast.method_body
|
79
|
+
replace_lvar(to_ast.method_body, to_path, lvar_suffix: lvar_suffix)
|
80
|
+
else
|
81
|
+
"()"
|
82
|
+
end
|
83
|
+
to_code = "((#{args}#{body}))"
|
84
|
+
replacements << {
|
85
|
+
from: node.location(path),
|
86
|
+
to: to_code
|
87
|
+
}
|
88
|
+
opt[:ignore_index] = 1 # Ignore arguments
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
return if replacements.empty?
|
93
|
+
return replace(ast, path, replacements).force_encoding(Encoding::UTF_8) # TODO: Support other encodings
|
94
|
+
end
|
95
|
+
|
96
|
+
attr_reader :klass, :method_name, :method
|
97
|
+
private :klass, :method_name, :method
|
98
|
+
|
99
|
+
# @param original_method [Method]
|
100
|
+
# @param replacements [Array<{from: Rinline::Location, to: String}>]
|
101
|
+
private def replace(original_ast, original_path, replacements)
|
102
|
+
ret = original_ast.to_source(original_path)
|
103
|
+
offset = -original_ast.location(original_path).first_index
|
104
|
+
|
105
|
+
replacements.each do |replacement|
|
106
|
+
from = replacement[:from]
|
107
|
+
to_code = replacement[:to]
|
108
|
+
|
109
|
+
ret[(from.first_index + offset)..(from.last_index + offset)] = to_code
|
110
|
+
offset += to_code.size - from.size
|
111
|
+
end
|
112
|
+
|
113
|
+
ret
|
114
|
+
end
|
115
|
+
|
116
|
+
private def replace_lvar(ast, path, lvar_suffix: gen_lvar_suffix)
|
117
|
+
replacements = []
|
118
|
+
|
119
|
+
ast.traverse do |node, opt|
|
120
|
+
case node.type
|
121
|
+
when :LASGN
|
122
|
+
next if node.lasgn_opasgn?
|
123
|
+
|
124
|
+
replacements << {
|
125
|
+
from: node.location_variable_name_of_lasgn(path),
|
126
|
+
to: "#{node.children[0]}#{lvar_suffix}",
|
127
|
+
}
|
128
|
+
when :LVAR
|
129
|
+
replacements << {
|
130
|
+
from: node.location(path),
|
131
|
+
to: "#{node.children[0]}#{lvar_suffix}"
|
132
|
+
}
|
133
|
+
when :OP_ASGN_OR
|
134
|
+
opt[:ignore_index] = 0
|
135
|
+
when :OP_ASGN_AND
|
136
|
+
opt[:ignore_index] = 0
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
replace(ast, path, replacements)
|
141
|
+
end
|
142
|
+
|
143
|
+
private def assign_args(method_node, fcall_node, fcall_path, lvar_suffix)
|
144
|
+
params = method_node.children[0]
|
145
|
+
args = fcall_node.fcall_args.array_content
|
146
|
+
args.map.with_index do |arg, index|
|
147
|
+
"#{params[index]}#{lvar_suffix} = #{arg.to_source(fcall_path)}"
|
148
|
+
end.join(';') + ';'
|
149
|
+
end
|
150
|
+
|
151
|
+
private def gen_lvar_suffix
|
152
|
+
"__#{SecureRandom.hex(5)}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Rinline
|
2
|
+
class Runner
|
3
|
+
class << self
|
4
|
+
attr_accessor :current
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_accessor :debug, :iseq_threshold
|
8
|
+
attr_reader :file_cache
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@debug = false
|
12
|
+
@iseq_threshold = 50
|
13
|
+
@file_cache = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def optimize_instance_method(klass, method_name)
|
17
|
+
debug_print "optimizing: #{klass}##{method_name}"
|
18
|
+
optimized = Optimizer.optimize(klass, method_name)
|
19
|
+
unless optimized
|
20
|
+
debug_print "skipped: #{klass}##{method_name}"
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
klass.class_eval "undef :#{method_name}; #{optimized}"
|
25
|
+
debug_print "optimized: #{klass}##{method_name}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def optimize_instance_methods(klass)
|
29
|
+
klass.instance_methods(false).each do |method|
|
30
|
+
optimize_instance_method(klass, method)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def optimize_class(klass)
|
35
|
+
debug_print "class: #{klass}"
|
36
|
+
optimize_instance_methods(klass)
|
37
|
+
optimize_instance_methods(klass.singleton_class)
|
38
|
+
end
|
39
|
+
|
40
|
+
alias optimize_module optimize_class
|
41
|
+
|
42
|
+
def optimize_namespace(mod)
|
43
|
+
debug_print "namespace: #{mod}"
|
44
|
+
optimize_module(mod)
|
45
|
+
constants = mod.constants
|
46
|
+
constants -= Struct.constants if mod < Struct
|
47
|
+
constants.each do |child|
|
48
|
+
child = mod.const_get(child)
|
49
|
+
optimize_namespace(child) if child.is_a?(Module)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def debug_print(*msg)
|
54
|
+
$stderr.puts(*msg) if debug
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/rinline.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "rinline/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "rinline"
|
7
|
+
spec.version = Rinline::VERSION
|
8
|
+
spec.authors = ["Masataka Pocke Kuwabara"]
|
9
|
+
spec.email = ["kuwabara@pocke.me"]
|
10
|
+
|
11
|
+
spec.summary = %q{Inline expansion for Ruby}
|
12
|
+
spec.description = %q{Inline expansion for Ruby}
|
13
|
+
spec.homepage = "https://github.com/pocke/rinline"
|
14
|
+
|
15
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", ">= 2"
|
31
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
32
|
+
spec.add_development_dependency 'minitest', '>= 5'
|
33
|
+
spec.add_development_dependency 'rr'
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rinline
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Masataka Pocke Kuwabara
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-05-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rr
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Inline expansion for Ruby
|
70
|
+
email:
|
71
|
+
- kuwabara@pocke.me
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- README.md
|
79
|
+
- Rakefile
|
80
|
+
- benchmark/simple.rb
|
81
|
+
- bin/console
|
82
|
+
- bin/setup
|
83
|
+
- lib/rinline.rb
|
84
|
+
- lib/rinline/ext/ast_ext.rb
|
85
|
+
- lib/rinline/ext/iseq_ext.rb
|
86
|
+
- lib/rinline/ext/method_ext.rb
|
87
|
+
- lib/rinline/location.rb
|
88
|
+
- lib/rinline/optimizer.rb
|
89
|
+
- lib/rinline/runner.rb
|
90
|
+
- lib/rinline/version.rb
|
91
|
+
- rinline.gemspec
|
92
|
+
homepage: https://github.com/pocke/rinline
|
93
|
+
licenses: []
|
94
|
+
metadata:
|
95
|
+
homepage_uri: https://github.com/pocke/rinline
|
96
|
+
source_code_uri: https://github.com/pocke/rinline
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubygems_version: 3.0.3
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Inline expansion for Ruby
|
116
|
+
test_files: []
|