yomikomu 0.1.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 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: []