yomikomu 0.1.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
+ SHA1:
3
+ metadata.gz: c79155668190a8c88087c6c5742860d5a67d838a
4
+ data.tar.gz: 48d6334da030db6727f082884982fb3046d7d4e7
5
+ SHA512:
6
+ metadata.gz: 2e630562b6fcc1e40d51e8dd22aae77b7048ffe64a3433a229fe8a0ae8c85be30cc6a1af4c0f2780d00fb74ebf5f2689d3cf06b0f335d064d408e9a06793bbd7
7
+ data.tar.gz: 03f1ae8cc3d2dc1e5b4c181db83c76d29d1d39cea9e3cbec3ec9a94d07e65a25a98c1f07783fc027415a6860004321aa2d280e29c60fccb1e1a2ea3147283569
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yomikomu.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Koichi Sasada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # Yomikomu
2
+
3
+ * `yomikomu` gem enables to load compiled instruction sequences (bytecodes).
4
+ * `kakidasu` command compiles and stores compiled instruction sequences (bytecodes).
5
+
6
+ This gem requires Ruby 2.3.0.
7
+ Most of code is ported from `ruby/sample/iseq_load.rb`.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'yomikomu'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install yomikomu
24
+
25
+ ## Usage
26
+
27
+ ### Configuration
28
+
29
+ You can use the following configuration with environment variables.
30
+
31
+ * YOMIKOMU_STORAGE (default: fs): choose storage type.
32
+ * 'fs' (default) stores binaries in the same directory (for examlple, `x.rb` will be compiled to `x.rb.yarb` in the same directory).
33
+ * 'fs2' stores binaries in specific directory.
34
+ * 'dbm' stores binaries using dbm
35
+ * YOMIKOMU_STORAGE_DIR (default: "~/.ruby_binaries"): choose directory where binary files are stored.
36
+ * YOMIKOMU_AUTO_COMPILE (default: false): if this value is `true`, then compile all required scripts implicitly.
37
+ * YOMIKOMU_DEBUG (default: not defined): show many information.
38
+
39
+ ### Compile and store instruction sequences
40
+
41
+ You only need to use the following command.
42
+
43
+ ```
44
+ $ kakidasu [file or dir] ...
45
+ ```
46
+
47
+ Compile specified file or files (*.rb) in specified directory.
48
+ If no files or directories are specified, then use "libdir" of installed Ruby.
49
+
50
+ ### Load compiled binary
51
+
52
+ You only need to require `yomikomu`.
53
+
54
+ ## Development
55
+
56
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
57
+
58
+ 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).
59
+
60
+ ## Contributing
61
+
62
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ko1/yomikomu.
63
+
64
+
65
+ ## License
66
+
67
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
68
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "yomikomu"
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
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/exe/kakidasu ADDED
@@ -0,0 +1,53 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'optparse'
6
+
7
+ verbose = false
8
+ executor = nil
9
+
10
+ opts = OptionParser.new{|o|
11
+ o.on('--verify [original script]', 'verify mode'){
12
+ executor = Proc.new{|file|
13
+ raise "TODO"
14
+ }
15
+ }
16
+ o.on('--remove [original script]', 'remove specific compiled iseq'){
17
+ executor = Proc.new{|file|
18
+ ::Yomikomu.remove_compiled_iseq(file)
19
+ }
20
+ }
21
+ o.on('--remove-all', 'remove all compiled iseq'){
22
+ ::Yomikomu.remove_all_compiled_iseq
23
+ }
24
+ o.on('-v', '--verbose'){
25
+ $VERBOSE = true
26
+ ENV['YOMIKOMU_DEBUG'] = 'true'
27
+ }
28
+ }
29
+
30
+ executor = Proc.new{|file|
31
+ begin
32
+ ::Yomikomu.compile_and_store_iseq(file)
33
+ rescue SyntaxError => e
34
+ STDERR.puts e
35
+ end
36
+ } unless executor # default
37
+
38
+ opts.parse!(ARGV)
39
+
40
+ require 'yomikomu'
41
+ require 'rbconfig'
42
+ paths = ARGV.empty? ? [RbConfig::CONFIG['libdir']] : ARGV
43
+
44
+ paths.each{|path|
45
+ if File.directory?(path)
46
+ pattern = File.join(path, '**/*.rb')
47
+ Dir.glob(pattern){|file|
48
+ executor.call(file)
49
+ }
50
+ else
51
+ executor.call(path)
52
+ end
53
+ }
@@ -0,0 +1,3 @@
1
+ module Yomikomu
2
+ VERSION = "0.1.0"
3
+ end
data/lib/yomikomu.rb ADDED
@@ -0,0 +1,234 @@
1
+ require "yomikomu/version"
2
+
3
+ module Yomikomu
4
+ class NullStorage
5
+ def load_iseq fname; end
6
+ def compile_and_store_iseq fname; end
7
+ def remove_compiled_iseq fname; end
8
+ end
9
+
10
+ STATISTICS = Hash.new(0)
11
+
12
+ unless yomu_dir = ENV['YOMIKOMU_STORAGE_DIR']
13
+ yomu_dir = File.expand_path("~/.ruby_binaries")
14
+ unless File.exist?(yomu_dir)
15
+ Dir.mkdir(yomu_dir)
16
+ end
17
+ end
18
+ YOMIKOMU_PREFIX = "#{yomu_dir}/cb."
19
+ YOMIKOMU_AUTO_COMPILE = ENV['YOMIKOMU_AUTO_COMPILE'] == 'true'
20
+
21
+ if $VERBOSE
22
+ def self.info
23
+ STDERR.puts "[YOMIKOMU:INFO] (pid:#{Process.pid}) #{yield}"
24
+ end
25
+ at_exit{
26
+ STDERR.puts "[YOMIKOMU:INFO] (pid:#{Process.pid}) " +
27
+ ::Yomikomu::STATISTICS.map{|k, v| "#{k}: #{v}"}.join(' ,')
28
+ }
29
+ else
30
+ def self.info
31
+ end
32
+ end
33
+
34
+ if ENV['YOMIKOMU_DEBUG'] == 'true'
35
+ def self.debug
36
+ STDERR.puts "[YOMIKOMU:DEBUG] (pid:#{Process.pid}) #{yield}"
37
+ end
38
+ else
39
+ def self.debug
40
+ end
41
+ end
42
+
43
+ class BasicStorage
44
+ def initialize
45
+ require 'digest/sha1'
46
+ end
47
+
48
+ def load_iseq fname
49
+ iseq_key = iseq_key_name(fname)
50
+
51
+ if compiled_iseq_exist?(fname, iseq_key) && compiled_iseq_is_younger?(fname, iseq_key)
52
+ ::Yomikomu::STATISTICS[:loaded] += 1
53
+ ::Yomikomu.debug{ "load #{fname} from #{iseq_key}" }
54
+ binary = read_compiled_iseq(fname, iseq_key)
55
+ iseq = RubyVM::InstructionSequence.load_from_binary(binary)
56
+ # p [extra_data(iseq.path), RubyVM::InstructionSequence.load_from_binary_extra_data(binary)]
57
+ # raise unless extra_data(iseq.path) == RubyVM::InstructionSequence.load_from_binary_extra_data(binary)
58
+ iseq
59
+ elsif YOMIKOMU_AUTO_COMPILE
60
+ compile_and_store_iseq(fname, iseq_key)
61
+ else
62
+ ::Yomikomu::STATISTICS[:ignored] += 1
63
+ ::Yomikomu.debug{ "ignored #{fname}" }
64
+ nil
65
+ end
66
+ end
67
+
68
+ def extra_data fname
69
+ "SHA-1:#{::Digest::SHA1.file(fname).digest}"
70
+ end
71
+
72
+ def compile_and_store_iseq fname, iseq_key = iseq_key_name(fname)
73
+ ::Yomikomu::STATISTICS[:compiled] += 1
74
+ ::Yomikomu.debug{ "[RUBY_COMPILED_FILE] compile #{fname} into #{iseq_key}" }
75
+ iseq = RubyVM::InstructionSequence.compile_file(fname)
76
+
77
+ binary = iseq.to_binary(extra_data(fname))
78
+ write_compiled_iseq(fname, iseq_key, binary)
79
+ iseq
80
+ end
81
+
82
+ # def remove_compiled_iseq fname; nil; end # should implement at sub classes
83
+
84
+ private
85
+
86
+ def iseq_key_name fname
87
+ fname
88
+ end
89
+
90
+ # should implement at sub classes
91
+ # def compiled_iseq_younger? fname, iseq_key; end
92
+ # def compiled_iseq_exist? fname, iseq_key; end
93
+ # def read_compiled_file fname, iseq_key; end
94
+ # def write_compiled_file fname, iseq_key, binary; end
95
+ end
96
+
97
+ class FSStorage < BasicStorage
98
+ def initialize
99
+ super
100
+ require 'fileutils'
101
+ @dir = YOMIKOMU_PREFIX + "files"
102
+ unless File.directory?(@dir)
103
+ FileUtils.mkdir_p(@dir)
104
+ end
105
+ end
106
+
107
+ def remove_compiled_iseq fname
108
+ iseq_key = iseq_key_name(fname)
109
+ if File.exist?(iseq_key)
110
+ Yomikomu.debug{ "rm #{iseq_key}" }
111
+ File.unlink(iseq_key)
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ def iseq_key_name fname
118
+ "#{fname}.yarb" # same directory
119
+ end
120
+
121
+ def compiled_iseq_exist? fname, iseq_key
122
+ File.exist?(iseq_key)
123
+ end
124
+
125
+ def compiled_iseq_is_younger? fname, iseq_key
126
+ File.mtime(iseq_key) >= File.mtime(fname)
127
+ end
128
+
129
+ def read_compiled_iseq fname, iseq_key
130
+ File.binread(iseq_key)
131
+ end
132
+
133
+ def write_compiled_iseq fname, iseq_key, binary
134
+ File.binwrite(iseq_key, binary)
135
+ end
136
+
137
+ def remove_all_compiled_iseq
138
+ raise "unsupported"
139
+ end
140
+ end
141
+
142
+ class FS2Storage < FSStorage
143
+ def iseq_key_name fname
144
+ File.join(@dir, fname.gsub(/[^A-Za-z0-9\._-]/){|c| '%02x' % c.ord} + '.yarb') # special directory
145
+ end
146
+
147
+ def remove_all_compiled_iseq
148
+ Dir.glob(File.join(@dir, '**/*.yarb')){|path|
149
+ Yomikomu.debug{ "rm #{path}" }
150
+ FileUtils.rm(path)
151
+ }
152
+ end
153
+ end
154
+
155
+ class DBMStorage < BasicStorage
156
+ def initialize
157
+ require 'dbm'
158
+ @db = DBM.open(YOMIKOMU_PREFIX+'db')
159
+ end
160
+
161
+ def remove_compiled_iseq fname
162
+ @db.delete fname
163
+ end
164
+
165
+ private
166
+
167
+ def date_key_name fname
168
+ "date.#{fname}"
169
+ end
170
+
171
+ def iseq_key_name fname
172
+ "body.#{fname}"
173
+ end
174
+
175
+ def compiled_iseq_exist? fname, iseq_key
176
+ @db.has_key? iseq_key
177
+ end
178
+
179
+ def compiled_iseq_is_younger? fname, iseq_key
180
+ date_key = date_key_name(fname)
181
+ if @db.has_key? date_key
182
+ @db[date_key].to_i >= File.mtime(fname).to_i
183
+ end
184
+ end
185
+
186
+ def read_compiled_iseq fname, iseq_key
187
+ @db[iseq_key]
188
+ end
189
+
190
+ def write_compiled_iseq fname, iseq_key, binary
191
+ date_key = date_key_name(fname)
192
+ @db[iseq_key] = binary
193
+ @db[date_key] = Time.now.to_i
194
+ end
195
+ end
196
+
197
+ def self.compile_and_store_iseq fname
198
+ STORAGE.compile_and_store_iseq fname
199
+ end
200
+
201
+ def self.remove_compiled_iseq fname
202
+ STORAGE.remove_compiled_iseq fname
203
+ end
204
+
205
+ def self.remove_all_compiled_iseq
206
+ STORAGE.remove_all_compiled_iseq
207
+ end
208
+
209
+ def self.verify_compiled_iseq fname
210
+ STORAGE.verify_compiled_iseq fname
211
+ end
212
+
213
+ # select storage
214
+ STORAGE = case ENV['YOMIKOMU_STORAGE']
215
+ when 'dbm'
216
+ DBMStorage.new
217
+ when 'fs'
218
+ FSStorage.new
219
+ when 'fs2'
220
+ FS2Storage.new
221
+ when 'null'
222
+ NullStorage.new
223
+ else
224
+ FSStorage.new
225
+ end
226
+
227
+ Yomikomu.info{ "[RUBY_YOMIKOMU] use #{STORAGE.class}" }
228
+ end
229
+
230
+ class RubyVM::InstructionSequence
231
+ def self.load_iseq fname
232
+ ::Yomikomu::STORAGE.load_iseq(fname)
233
+ end
234
+ end
data/yomikomu.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'yomikomu/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "yomikomu"
8
+ spec.version = Yomikomu::VERSION
9
+ spec.authors = ["Koichi Sasada"]
10
+ spec.email = ["ko1@atdot.net"]
11
+
12
+ spec.summary = %q{Dump compiled iseq by binary (kakidasu) and load binary (yomidasu).}
13
+ spec.description = %q{Dump compiled iseq by binary (kakidasu) and load binary (yomidasu).}
14
+ spec.homepage = "http://github.com/ko1/yomikomu"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "minitest"
25
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yomikomu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Koichi Sasada
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-12-12 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: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.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: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Dump compiled iseq by binary (kakidasu) and load binary (yomidasu).
56
+ email:
57
+ - ko1@atdot.net
58
+ executables:
59
+ - kakidasu
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - exe/kakidasu
72
+ - lib/yomikomu.rb
73
+ - lib/yomikomu/version.rb
74
+ - yomikomu.gemspec
75
+ homepage: http://github.com/ko1/yomikomu
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.5.0
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Dump compiled iseq by binary (kakidasu) and load binary (yomidasu).
99
+ test_files: []