minigems 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Fabien Franzen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,40 @@
1
+ MiniGems
2
+ ========
3
+
4
+ A lightweight drop-in replacement for rubygems to facilitate faster loading of
5
+ gems as well as reducing memory consumption considerably. Depending on the
6
+ amount of gems you have installed about 10-20 MB less RAM will be used, compared
7
+ to the full rubygems library version, which keeps a cache of all gems and files
8
+ referenced by them.
9
+
10
+ Minigems handles loading of required gems from your scripts. If however, other
11
+ functionality is needed, the full rubygems library will be loaded automatically
12
+ to continue normal operation.
13
+
14
+ You'll need to run 'sudo minigem setup' to get started; this will install
15
+ minigems.rb in your site_ruby directory, which makes it available to all your
16
+ ruby scripts.
17
+
18
+ MiniGems is enabled on a per-gem basis. To do so, you run 'minigem prepare', for
19
+ example, say we want the binary executables for merb-core (the 'merb' command)
20
+ to use minigems:
21
+
22
+ sudo minigem prepare merb-core
23
+
24
+ And to revert back to rubygems:
25
+
26
+ sudo minigem revert merb-core
27
+
28
+ To use minigems in your own scripts, use the following construct, instead of the
29
+ common 'require "rubygems"' statement:
30
+
31
+ begin
32
+ require 'minigems'
33
+ rescue LoadError
34
+ require 'rubygems'
35
+ end
36
+
37
+ There's currently a patch pending on RubyForge, to get minigems into the
38
+ standard, rubygems system. If you like minigems, please post a vote/followup:
39
+
40
+ http://rubyforge.org/tracker/?func=detail&atid=577&aid=21979&group_id=126
data/Rakefile ADDED
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require File.join(File.dirname(__FILE__), 'lib', 'minigems')
4
+
5
+ ##############################################################################
6
+ # Package && release
7
+ ##############################################################################
8
+ RUBY_FORGE_PROJECT = "merb"
9
+ PROJECT_URL = "http://merbivore.com"
10
+ PROJECT_SUMMARY = "Lighweight drop-in replacement for rubygems."
11
+ PROJECT_DESCRIPTION = PROJECT_SUMMARY
12
+
13
+ GEM_AUTHOR = "Fabien Franzen"
14
+ GEM_EMAIL = "info@atelierfabien.be"
15
+
16
+ GEM_NAME = "minigems"
17
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
18
+ GEM_VERSION = (Gem::MiniGems::VERSION || "0.9.0") + PKG_BUILD
19
+
20
+ RELEASE_NAME = "REL #{GEM_VERSION}"
21
+
22
+ spec = Gem::Specification.new do |s|
23
+ s.rubyforge_project = RUBY_FORGE_PROJECT
24
+ s.name = GEM_NAME
25
+ s.version = GEM_VERSION
26
+ s.platform = Gem::Platform::RUBY
27
+ s.has_rdoc = true
28
+ s.extra_rdoc_files = ["README", "LICENSE"]
29
+ s.summary = PROJECT_SUMMARY
30
+ s.description = PROJECT_DESCRIPTION
31
+ s.author = GEM_AUTHOR
32
+ s.email = GEM_EMAIL
33
+ s.homepage = PROJECT_URL
34
+ s.bindir = "bin"
35
+ s.executables = %w( minigem )
36
+ s.require_path = "lib"
37
+ s.files = %w(LICENSE README Rakefile) + Dir.glob("{lib,bin,spec}/**/*")
38
+ s.post_install_message = "Run 'minigem' for instructions on how to proceed."
39
+ end
40
+
41
+ def sudo
42
+ ENV['MERB_SUDO'] ||= "sudo"
43
+ sudo = windows? ? "" : ENV['MERB_SUDO']
44
+ end
45
+
46
+ def windows?
47
+ (PLATFORM =~ /win32|cygwin/) rescue nil
48
+ end
49
+
50
+ def install_home
51
+ ENV['GEM_HOME'] ? "-i #{ENV['GEM_HOME']}" : ""
52
+ end
53
+
54
+ Rake::GemPackageTask.new(spec) do |pkg|
55
+ pkg.gem_spec = spec
56
+ end
57
+
58
+ desc "removes any generated content"
59
+ task :clean do
60
+ FileUtils.rm_rf "clobber/*"
61
+ FileUtils.rm_rf "pkg/*"
62
+ end
63
+
64
+ desc "create a gemspec file"
65
+ task :make_spec do
66
+ File.open("#{GEM}.gemspec", "w") do |file|
67
+ file.puts spec.to_ruby
68
+ end
69
+ end
70
+
71
+ desc "Install the gem"
72
+ task :install => [:clean, :package] do
73
+ sh %{#{sudo} gem install #{install_home} pkg/#{GEM_NAME}-#{GEM_VERSION} --no-wrapper --no-update-sources --no-rdoc --no-ri}
74
+ end
75
+
76
+ namespace :jruby do
77
+
78
+ desc "Run :package and install the resulting .gem with jruby"
79
+ task :install => :package do
80
+ sh %{#{sudo} jruby -S gem install #{install_home} pkg/#{GEM_NAME}-#{GEM_VERSION}.gem --no-wrapper --no-rdoc --no-ri}
81
+ end
82
+
83
+ end
data/bin/minigem ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'minigems/script_helper'
4
+
5
+ include Gem::MiniGems::ScriptHelper
6
+
7
+ if ARGV.empty? || %w[-H --help].detect { |o| ARGV.index(o) }
8
+ # Show some usage information.
9
+ program = File.basename($0)
10
+ puts "Usage:"
11
+ puts " #{program} setup"
12
+ puts " #{program} prepare GEMNAME [GEMNAME ...]"
13
+ puts " #{program} revert GEMNAME [GEMNAME ...]"
14
+ puts " #{program} install GEMNAME [GEMNAME ...] [options] -- --build-flags [options]"
15
+ puts " #{program} update GEMNAME [GEMNAME ...] [options]"
16
+ puts " #{program} <command> GEMNAME [GEMNAME ...] [options]"
17
+ puts " "
18
+ puts "Description:"
19
+ puts " Manage 'minigems': a lightweight drop-in replacement for the rubygems"
20
+ puts " to facilitate faster loading of gems as well as reducing memory"
21
+ puts " consumption considerably. Depending on the amount of gems you have"
22
+ puts " installed about 10-20 MB less RAM will be used, compared to the full"
23
+ puts " rubygems library version, which keeps a cache of all gems and files"
24
+ puts " referenced by them."
25
+ puts " "
26
+ puts " Minigems handles loading of required gems from your scripts. If however,"
27
+ puts " other functionality is needed, the full rubygems library will be loaded"
28
+ puts " automatically to continue normal operation."
29
+ puts " "
30
+ puts " To use minigems in your own scripts, use the following construct,"
31
+ puts " instead of the common 'require \"rubygems\"' statement:"
32
+ puts " "
33
+ puts " begin"
34
+ puts " require 'minigems'"
35
+ puts " rescue LoadError"
36
+ puts " require 'rubygems'"
37
+ puts " end"
38
+ puts " "
39
+ puts "Options:"
40
+ puts " -H, --help Show this message and quit."
41
+ puts " -v, --version Show the program version number and quit."
42
+ elsif ARGV[0] == 'setup'
43
+ # Install minigems.rb in the ruby search path.
44
+ ensure_in_load_path!(true)
45
+ elsif ARGV[0] == 'uninstall'
46
+ command = ARGV.shift.to_sym # skip command argument
47
+ # Uninstall minigems.rb from the ruby search path.
48
+ remove_minigems! if ARGV.empty?
49
+ # Remove any gems that have been specified.
50
+ unless ARGV.empty?
51
+ cmd = Gem::GemRunner.new.run_command(command, ARGV)
52
+ cmd.get_all_referenced_gem_specs.each do |gemspec|
53
+ adapt_executables_for(gemspec)
54
+ end
55
+ end
56
+ elsif ARGV[0] == 'prepare'
57
+ # Adapt a gems' executable wrapper to use minigems.
58
+ ARGV.shift # skip prepare command argument
59
+ ensure_in_load_path!(ARGV.empty?)
60
+ ARGV.each do |gem_name|
61
+ next unless (gem_spec = Gem.source_index.find_name(gem_name).sort_by { |g| g.version }.last)
62
+ adapt_executables_for(gem_spec)
63
+ end
64
+ elsif ARGV[0] == 'revert'
65
+ # Adapt a gems' executable wrapper to use rubygems.
66
+ ARGV.shift # skip prepare command argument
67
+ ensure_in_load_path!(ARGV.empty?)
68
+ ARGV.each do |gem_name|
69
+ next unless (gem_spec = Gem.source_index.find_name(gem_name).sort_by { |g| g.version }.last)
70
+ revert_executables_for(gem_spec)
71
+ end
72
+ elsif ARGV[0] == 'install' || ARGV[0] == 'update'
73
+ # Install or update a rubygem and prepare it for minigems.
74
+ command = ARGV.shift.to_sym # skip command argument
75
+ ensure_in_load_path!(ARGV.empty?)
76
+ # Remove any gems that have been specified.
77
+ unless ARGV.empty?
78
+ cmd = Gem::GemRunner.new.run_command(command, ARGV)
79
+ cmd.get_all_referenced_gem_specs.each do |gemspec|
80
+ adapt_executables_for(gemspec)
81
+ end
82
+ end
83
+ else
84
+ # Proxy to rubygems for any other command.
85
+ #
86
+ # We need to preserve the original ARGV to use for passing gem options
87
+ # to source gems. If there is a -- in the line, strip all options after
88
+ # it...its for the source building process.
89
+ args = !ARGV.include?("--") ? ARGV.clone : ARGV[0...ARGV.index("--")]
90
+ Gem::GemRunner.new.run(args)
91
+ end
data/lib/minigems.rb ADDED
@@ -0,0 +1,267 @@
1
+ module Gem
2
+ module MiniGems
3
+ VERSION = "0.9.0"
4
+
5
+ # The next line needs to be kept exactly as shown; it's being replaced
6
+ # during minigems installation.
7
+ FULL_RUBYGEMS_METHODS = []
8
+
9
+ end
10
+ end
11
+
12
+ # Enable minigems unless rubygems has already loaded.
13
+ unless $LOADED_FEATURES.include?("rubygems.rb")
14
+
15
+ # Prevent full rubygems from loading
16
+ $LOADED_FEATURES << "rubygems.rb"
17
+ require "rubygems/version"
18
+ require "rubygems/rubygems_version"
19
+ require "rubygems/requirement"
20
+ require "rubygems/dependency"
21
+ require "rubygems/specification"
22
+ require "rbconfig"
23
+
24
+ module Kernel
25
+
26
+ def gem(name, *versions)
27
+ Gem.activate(name, *versions)
28
+ end
29
+
30
+ alias :gem_original_require :require
31
+
32
+ # We replace Ruby's require with our own, which is capable of
33
+ # loading gems on demand.
34
+ #
35
+ # When you call <tt>require 'x'</tt>, this is what happens:
36
+ # * If the file can be loaded from the existing Ruby loadpath, it
37
+ # is.
38
+ # * Otherwise, installed gems are searched for a file that matches.
39
+ # If it's found in gem 'y', that gem is activated (added to the
40
+ # loadpath).
41
+ #
42
+ # The normal <tt>require</tt> functionality of returning false if
43
+ # that file has already been loaded is preserved.
44
+ #
45
+ def require(path) # :nodoc:
46
+ gem_original_require path
47
+ rescue LoadError => load_error
48
+ if load_error.message =~ /#{Regexp.escape path}\z/ && Gem.activate(path)
49
+ gem_original_require(path)
50
+ else
51
+ raise load_error
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ module Gem
58
+
59
+ CORE_GEM_METHODS = Gem.methods(false)
60
+
61
+ class Exception < RuntimeError; end
62
+
63
+ class LoadError < ::LoadError
64
+ attr_accessor :name, :version_requirement
65
+ end
66
+
67
+ # Whether minigems is being used or full rubygems has taken over.
68
+ def self.minigems?
69
+ not const_defined?(:SourceIndex)
70
+ end
71
+
72
+ # Keep track of loaded gems, maps gem name to full_name.
73
+ def self.loaded_gems
74
+ @loaded_gems ||= {}
75
+ end
76
+
77
+ # Refresh the current 'cached' gems - in this case
78
+ # just the list of loaded gems.
79
+ def self.refresh
80
+ self.loaded_gems.clear
81
+ end
82
+
83
+ # See if a given gem is available.
84
+ def self.available?(name, *version_requirements)
85
+ version_requirements = Gem::Requirement.default if version_requirements.empty?
86
+ gem = Gem::Dependency.new(name, version_requirements)
87
+ not find(gem).nil?
88
+ end
89
+
90
+ # Activates an installed gem matching +gem+. The gem must satisfy
91
+ # +version_requirements+.
92
+ #
93
+ # Returns true if the gem is activated, false if it is already
94
+ # loaded, or an exception otherwise.
95
+ #
96
+ # Gem#activate adds the library paths in +gem+ to $LOAD_PATH. Before a Gem
97
+ # is activated its required Gems are activated. If the version information
98
+ # is omitted, the highest version Gem of the supplied name is loaded. If a
99
+ # Gem is not found that meets the version requirements or a required Gem is
100
+ # not found, a Gem::LoadError is raised.
101
+ #
102
+ # More information on version requirements can be found in the
103
+ # Gem::Requirement and Gem::Version documentation.
104
+ def self.activate(gem, *version_requirements)
105
+ if match = find(gem, *version_requirements)
106
+ # Load and initialize the gemspec
107
+ gem_spec = Gem::Specification.load(gem_path = match.first)
108
+ gem_spec.loaded_from = gem_path
109
+
110
+ # Raise an exception if the same spec has already been loaded - except for identical matches
111
+ if (already_loaded = self.loaded_gems[gem_spec.name]) && gem_spec.full_name != already_loaded
112
+ raise Gem::Exception, "can't activate #{gem_spec.name}, already activated #{already_loaded}"
113
+ # If it's an identical match, we're done activating
114
+ elsif already_loaded
115
+ return false
116
+ end
117
+
118
+ # Keep track of loaded gems - by name instead of full specs (memory!)
119
+ self.loaded_gems[gem_spec.name] = gem_spec.full_name
120
+
121
+ # Load dependent gems first
122
+ gem_spec.runtime_dependencies.each { |dep_gem| activate(dep_gem) }
123
+
124
+ # bin directory must come before library directories
125
+ gem_spec.require_paths.unshift(gem_spec.bindir) if gem_spec.bindir
126
+
127
+ # Add gem require paths to $LOAD_PATH
128
+ gem_spec.require_paths.reverse.each do |require_path|
129
+ $LOAD_PATH.unshift File.join(gem_spec.full_gem_path, require_path)
130
+ end
131
+ return true
132
+ else
133
+ unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
134
+ gem = Gem::Dependency.new(gem, version_requirements)
135
+ end
136
+ report_activate_error(gem)
137
+ end
138
+ end
139
+
140
+ # Helper method to find all current gem paths.
141
+ #
142
+ # Find the most recent gem versions' paths just by looking at the gem's
143
+ # directory version number. This is faster than parsing gemspec files
144
+ # at the expense of being less complete when it comes to require paths.
145
+ # That's why Gem.activate actually parses gemspecs instead of directories.
146
+ def self.latest_gem_paths
147
+ lookup = {}
148
+ gem_path_sets = self.path.map { |path| [path, Dir["#{path}/gems/*"]] }
149
+ gem_path_sets.each do |root_path, gems|
150
+ unless gems.empty?
151
+ gems.each do |gem_path|
152
+ if matches = File.basename(File.basename(gem_path)).match(/^(.*?)-([\d\.]+)$/)
153
+ name, version_no = matches.captures[0,2]
154
+ version = Gem::Version.new(version_no)
155
+ if !lookup[name] || (lookup[name] && lookup[name][1] < version)
156
+ lookup[name] = [gem_path, version]
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ lookup.collect { |name,(gem_path, version)| gem_path }.sort
163
+ end
164
+
165
+ # Array of paths to search for Gems.
166
+ def self.path
167
+ @path ||= begin
168
+ paths = [ENV['GEM_PATH'] ? ENV['GEM_PATH'] : default_path]
169
+ paths << APPLE_GEM_HOME if defined?(APPLE_GEM_HOME) && !ENV['GEM_PATH']
170
+ paths
171
+ end
172
+ end
173
+
174
+ # Default gem load path.
175
+ def self.default_path
176
+ @default_path ||= if defined? RUBY_FRAMEWORK_VERSION then
177
+ File.join File.dirname(RbConfig::CONFIG["sitedir"]), 'Gems',
178
+ RbConfig::CONFIG["ruby_version"]
179
+ elsif defined? RUBY_ENGINE then
180
+ File.join RbConfig::CONFIG["libdir"], RUBY_ENGINE, 'gems',
181
+ RbConfig::CONFIG["ruby_version"]
182
+ else
183
+ File.join RbConfig::CONFIG["libdir"], 'ruby', 'gems',
184
+ RbConfig::CONFIG["ruby_version"]
185
+ end
186
+ end
187
+
188
+ # Reset the +path+ value. The next time +path+ is requested,
189
+ # the values will be calculated from scratch.
190
+ def self.clear_paths
191
+ @path = nil
192
+ end
193
+
194
+ # Catch calls to full rubygems methods - once accessed
195
+ # the current Gem methods are overridden.
196
+ def self.method_missing(m, *args, &blk)
197
+ if Gem::MiniGems::FULL_RUBYGEMS_METHODS.include?(m.to_s)
198
+ load_full_rubygems!
199
+ return send(m, *args, &blk)
200
+ end
201
+ super
202
+ end
203
+
204
+ # Catch references to full rubygems constants - once accessed
205
+ # the current Gem constants are merged.
206
+ def self.const_missing(const)
207
+ load_full_rubygems!
208
+ if Gem.const_defined?(const)
209
+ Gem.const_get(const)
210
+ else
211
+ super
212
+ end
213
+ end
214
+
215
+ protected
216
+
217
+ # Find all gem specs for the requested gem.
218
+ def self.find(gem, *version_requirements)
219
+ version_requirements = Gem::Requirement.default if version_requirements.empty?
220
+ unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
221
+ gem = Gem::Dependency.new(gem, version_requirements)
222
+ end
223
+
224
+ gemspec_sets = self.path.map { |path| [path, Dir["#{path}/specifications/#{gem.name}-*.gemspec"]] }
225
+ versions = gemspec_sets.inject([]) do |versions, (root_path, gems)|
226
+ unless gems.empty?
227
+ gems.each do |gemspec_path|
228
+ if (version_no = gemspec_path[/-([\d\.]+)\.gemspec$/, 1]) &&
229
+ gem.version_requirements.satisfied_by?(version = Gem::Version.new(version_no))
230
+ versions << [gemspec_path, version]
231
+ end
232
+ end
233
+ end
234
+ versions
235
+ end
236
+ # Find the best (highest) matching gem version
237
+ versions.max { |a, b| a.last <=> b.last }
238
+ end
239
+
240
+ # Report a load error during activation.
241
+ def self.report_activate_error(gem)
242
+ error = Gem::LoadError.new("Could not find RubyGem #{gem.name} (#{gem.version_requirements})\n")
243
+ error.name = gem.name
244
+ error.version_requirement = gem.version_requirements
245
+ raise error
246
+ end
247
+
248
+ # Load the full rubygems suite, at which point all minigems logic
249
+ # is being overridden, so all regular methods and classes are available.
250
+ def self.load_full_rubygems!
251
+ # Clear out any minigems methods
252
+ class << self
253
+ (MINIGEMS_METHODS - CORE_GEM_METHODS).each do |method_name|
254
+ undef_method method_name
255
+ end
256
+ end
257
+ # Re-alias the 'require' method back to its original.
258
+ ::Kernel.module_eval { alias_method :require, :gem_original_require }
259
+ require $LOADED_FEATURES.delete("rubygems.rb")
260
+ end
261
+
262
+ # Record all minigems methods - except the minigems? predicate method.
263
+ MINIGEMS_METHODS = Gem.methods(false) - ["minigems?"]
264
+
265
+ end
266
+
267
+ end
@@ -0,0 +1,22 @@
1
+ SHEBANG
2
+
3
+ # This file was generated by MiniGems (standalone version).
4
+ #
5
+ # The application 'EXECUTABLE_NAME' is installed as part of a gem (GEM_NAME),
6
+ # and this file is here to facilitate running it.
7
+
8
+ begin
9
+ require 'GEM_MODE'
10
+ rescue LoadError
11
+ require 'rubygems'
12
+ end
13
+
14
+ version = ">= 0"
15
+
16
+ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
17
+ version = $1
18
+ ARGV.shift
19
+ end
20
+
21
+ gem 'GEM_NAME', version
22
+ load 'EXECUTABLE_NAME'
@@ -0,0 +1,138 @@
1
+ require 'rubygems/gem_runner'
2
+ require 'rubygems/exceptions'
3
+ require 'rubygems/commands/install_command'
4
+ require 'rubygems/commands/update_command'
5
+ require 'fileutils'
6
+
7
+ module Gem
8
+
9
+ class GemRunner
10
+ def run_command(command_name, args)
11
+ args.unshift command_name.to_s
12
+ do_configuration(args)
13
+ cmd_manager = @command_manager_class.instance
14
+ config_args = Gem.configuration[command_name.to_s]
15
+ config_args = case config_args
16
+ when String
17
+ config_args.split ' '
18
+ else
19
+ Array(config_args)
20
+ end
21
+ Command.add_specific_extra_args(command_name, config_args)
22
+ cmd_manager.run(Gem.configuration.args)
23
+ rescue Gem::SystemExitException
24
+ cmd_manager.cmd
25
+ ensure
26
+ cmd_manager.cmd
27
+ end
28
+ end
29
+
30
+ class Command
31
+ def get_all_referenced_gem_specs
32
+ get_all_gem_names.map { |name| Gem.source_index.search(name).last }.compact
33
+ end
34
+ end
35
+
36
+ class CommandManager
37
+ attr_accessor :cmd
38
+ alias :original_find_command :find_command
39
+ def find_command(cmd_name)
40
+ self.cmd = original_find_command(cmd_name)
41
+ self.cmd
42
+ end
43
+ end
44
+
45
+ module MiniGems
46
+ module ScriptHelper
47
+
48
+ def minigems_path
49
+ @minigems_path ||= begin
50
+ if (gem_spec = Gem.source_index.find_name('minigems').sort_by { |g| g.version }.last)
51
+ gem_spec.full_gem_path
52
+ else
53
+ raise "Minigems gem not found!"
54
+ end
55
+ end
56
+ end
57
+
58
+ def adapt_executables_for(gemspec)
59
+ gemspec.executables.each do |executable|
60
+ next if executable == 'minigem' # better not modify minigem itself
61
+ if File.exists?(wrapper_path = File.join(Gem.bindir, executable))
62
+ wrapper_code = interpolate_wrapper(gemspec.name, executable)
63
+ begin
64
+ if File.open(wrapper_path, 'w') { |f| f.write(wrapper_code) }
65
+ puts "Adapted #{wrapper_path} to use minigems instead of rubygems."
66
+ else
67
+ puts "Failed to adapt #{wrapper_path} - maybe you need sudo permissions?"
68
+ end
69
+ rescue Errno::EACCES => e
70
+ puts "Failed to adapt #{wrapper_path} - maybe you need sudo permissions?"
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ def revert_executables_for(gemspec)
77
+ gemspec.executables.each do |executable|
78
+ next if executable == 'minigem' # better not modify minigem itself
79
+ if File.exists?(wrapper_path = File.join(Gem.bindir, executable))
80
+ wrapper_code = interpolate_wrapper(gemspec.name, executable, 'rubygems')
81
+ begin
82
+ if File.open(wrapper_path, 'w') { |f| f.write(wrapper_code) }
83
+ puts "Reverted #{wrapper_path} to use rubygems instead of minigems."
84
+ else
85
+ puts "Failed to revert #{wrapper_path} - maybe you need sudo permissions?"
86
+ end
87
+ rescue Errno::EACCES => e
88
+ puts "Failed to revert #{wrapper_path} - maybe you need sudo permissions?"
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def ensure_in_load_path!(force = false)
95
+ install_path = File.join(Gem::ConfigMap[:sitelibdir], 'minigems.rb')
96
+ if force || !File.exists?(install_path)
97
+ if File.exists?(source_path = File.join(minigems_path, 'lib', 'minigems.rb'))
98
+ begin
99
+ minigems_code = File.read(source_path)
100
+ placeholder = "FULL_RUBYGEMS_METHODS = []"
101
+ replacement = "FULL_RUBYGEMS_METHODS = %w[\n "
102
+ replacement << (Gem.methods - Object.methods).sort.join("\n ")
103
+ replacement << "\n ]"
104
+ File.open(install_path, 'w') do |f|
105
+ f.write minigems_code.sub(placeholder, replacement)
106
+ end
107
+ puts "Installed minigems at #{install_path}"
108
+ rescue Errno::EACCES
109
+ puts "Could not install minigems at #{install_path} (try sudo)"
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ def remove_minigems!
116
+ if File.exists?(install_path = File.join(Gem::ConfigMap[:sitelibdir], 'minigems.rb'))
117
+ if FileUtils.rm(install_path)
118
+ puts "Succesfully removed #{install_path}"
119
+ return
120
+ end
121
+ end
122
+ rescue => e
123
+ puts e.message
124
+ puts "Could not remove #{install_path} (try sudo)"
125
+ end
126
+
127
+ def interpolate_wrapper(gem_name, executable_name, mode = 'minigems')
128
+ @template_code ||= File.read(File.join(minigems_path, 'lib', 'minigems', 'executable_wrapper'))
129
+ vars = { 'GEM_NAME' => gem_name, 'EXECUTABLE_NAME' => executable_name }
130
+ vars['SHEBANG'] = "#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
131
+ vars['GEM_MODE'] = mode
132
+ vars.inject(@template_code) { |str,(k,v)| str.gsub(k,v) }
133
+ end
134
+
135
+ end
136
+ end
137
+
138
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 YOUR NAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ gem_with_lib
2
+ ============
3
+
4
+ A gem that provides...
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+
6
+ GEM = "gem_with_lib"
7
+ GEM_VERSION = "0.0.1"
8
+ AUTHOR = "Your Name"
9
+ EMAIL = "Your Email"
10
+ HOMEPAGE = "http://example.com"
11
+ SUMMARY = "A gem that provides..."
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = GEM
15
+ s.version = GEM_VERSION
16
+ s.platform = Gem::Platform::RUBY
17
+ s.has_rdoc = true
18
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.author = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+
25
+ # Uncomment this to add a dependency
26
+ # s.add_dependency "foo"
27
+
28
+ s.require_path = 'lib'
29
+ s.autorequire = GEM
30
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
31
+ end
32
+
33
+ Rake::GemPackageTask.new(spec) do |pkg|
34
+ pkg.gem_spec = spec
35
+ end
36
+
37
+ desc "install the gem locally"
38
+ task :install => [:package] do
39
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
40
+ end
41
+
42
+ desc "create a gemspec file"
43
+ task :make_spec do
44
+ File.open("#{GEM}.gemspec", "w") do |file|
45
+ file.puts spec.to_ruby
46
+ end
47
+ end
@@ -0,0 +1,4 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/<%= name %>.rb
@@ -0,0 +1,5 @@
1
+ module GemWithLib
2
+ VERSION = "0.0.1"
3
+ class Awesome
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 YOUR NAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ gem_with_lib
2
+ ============
3
+
4
+ A gem that provides...
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+
6
+ GEM = "gem_with_lib"
7
+ GEM_VERSION = "0.0.2"
8
+ AUTHOR = "Your Name"
9
+ EMAIL = "Your Email"
10
+ HOMEPAGE = "http://example.com"
11
+ SUMMARY = "A gem that provides..."
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = GEM
15
+ s.version = GEM_VERSION
16
+ s.platform = Gem::Platform::RUBY
17
+ s.has_rdoc = true
18
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.author = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+
25
+ # Uncomment this to add a dependency
26
+ # s.add_dependency "foo"
27
+
28
+ s.require_path = 'lib'
29
+ s.executables = %w( gem_with_lib )
30
+ s.autorequire = GEM
31
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
32
+ end
33
+
34
+ Rake::GemPackageTask.new(spec) do |pkg|
35
+ pkg.gem_spec = spec
36
+ end
37
+
38
+ desc "install the gem locally"
39
+ task :install => [:package] do
40
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
41
+ end
42
+
43
+ desc "create a gemspec file"
44
+ task :make_spec do
45
+ File.open("#{GEM}.gemspec", "w") do |file|
46
+ file.puts spec.to_ruby
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/<%= name %>.rb
@@ -0,0 +1 @@
1
+ #!/usr/bin/env ruby
@@ -0,0 +1,5 @@
1
+ module GemWithLib
2
+ VERSION = "0.0.2"
3
+ class Awesome
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{gem_with_lib}
3
+ s.version = "0.0.1"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Your Name"]
7
+ s.autorequire = %q{gem_with_lib}
8
+ s.date = %q{2008-08-17}
9
+ s.description = %q{A gem that provides...}
10
+ s.email = %q{Your Email}
11
+ s.extra_rdoc_files = ["README", "LICENSE", "TODO"]
12
+ s.files = ["LICENSE", "README", "Rakefile", "TODO", "lib/gem_with_lib.rb"]
13
+ s.has_rdoc = true
14
+ s.homepage = %q{http://example.com}
15
+ s.require_paths = ["lib"]
16
+ s.rubygems_version = %q{1.2.0}
17
+ s.summary = %q{A gem that provides...}
18
+
19
+ if s.respond_to? :specification_version then
20
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
21
+ s.specification_version = 2
22
+
23
+ if current_version >= 3 then
24
+ else
25
+ end
26
+ else
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{gem_with_lib}
3
+ s.version = "0.0.2"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Your Name"]
7
+ s.autorequire = %q{gem_with_lib}
8
+ s.date = %q{2008-08-19}
9
+ s.description = %q{A gem that provides...}
10
+ s.email = %q{Your Email}
11
+ s.extra_rdoc_files = ["README", "LICENSE", "TODO"]
12
+ s.files = ["LICENSE", "README", "Rakefile", "TODO", "lib/gem_with_lib.rb"]
13
+ s.has_rdoc = true
14
+ s.homepage = %q{http://example.com}
15
+ s.executables = %w( gem_with_lib )
16
+ s.require_paths = ["lib"]
17
+ s.rubygems_version = %q{1.2.0}
18
+ s.summary = %q{A gem that provides...}
19
+
20
+ if s.respond_to? :specification_version then
21
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
+ s.specification_version = 2
23
+
24
+ if current_version >= 3 then
25
+ else
26
+ end
27
+ else
28
+ end
29
+ end
@@ -0,0 +1,105 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'minigems')
2
+
3
+ # We can't use the spec runner, as that will already load or full gems!
4
+ gem "rspec"
5
+ require "spec"
6
+
7
+ describe Gem::MiniGems do
8
+
9
+ before do
10
+ # Setup rubygems from our spec fixtures directory
11
+ Gem.refresh
12
+ @gem_dir = File.join(File.dirname(__FILE__), "fixtures")
13
+ Gem.path.replace([@gem_dir])
14
+ end
15
+
16
+ after do
17
+ # Remove fixture load paths from $LOAD_PATH for specs
18
+ $LOAD_PATH.reject! { |path| path.index(@gem_dir) == 0 }
19
+ $LOADED_FEATURES.delete("gem_with_lib.rb")
20
+ # Make sure any loaded classes are removed
21
+ Object.send(:remove_const, "GemWithLib") if Object.const_defined?("GemWithLib")
22
+ Gem.should be_minigems
23
+ end
24
+
25
+ it "has a replaceable Gem.path" do
26
+ Gem.path.replace(["awesome"])
27
+ Gem.path.should == ["awesome"]
28
+ end
29
+
30
+ it "loads gems through the Kernel#require method" do
31
+ require("gem_with_lib").should be_true
32
+ lambda { GemWithLib::Awesome }.should_not raise_error(NameError)
33
+ GemWithLib::VERSION.should == "0.0.2"
34
+ end
35
+
36
+ it "lets you check for gem availability" do
37
+ Gem.available?("unknown_gem").should be_false
38
+ Gem.available?("gem_with_lib").should be_true
39
+ Gem.available?("gem_with_lib", "0.0.1").should be_true
40
+ Gem.available?("gem_with_lib", "0.0.2").should be_true
41
+ Gem.available?("gem_with_lib", ">0.0.1").should be_true
42
+ Gem.available?("gem_with_lib", ">0.0.2").should be_false
43
+ end
44
+
45
+ it "should raise Gem::LoadError if no matching gem was found" do
46
+ lambda { gem("unknown_gem") }.should raise_error(Gem::LoadError)
47
+ end
48
+
49
+ it "uses 'gem' to setup additional load path entries" do
50
+ gem_lib_path = File.join(@gem_dir, "gems", "gem_with_lib-0.0.2", "lib")
51
+ gem_bin_path = File.join(@gem_dir, "gems", "gem_with_lib-0.0.2", "bin")
52
+ $LOAD_PATH.should_not include(gem_lib_path)
53
+ gem("gem_with_lib").should be_true
54
+ $LOAD_PATH.first.should == gem_bin_path
55
+ $LOAD_PATH.should include(gem_lib_path)
56
+ $LOAD_PATH.select { |path| path == gem_lib_path }.length.should == 1
57
+ lambda { GemWithLib::Awesome }.should raise_error(NameError)
58
+ end
59
+
60
+ it "uses 'gem' to setup additional load path entries (for a specific gem version)" do
61
+ gem_lib_path = File.join(@gem_dir, "gems", "gem_with_lib-0.0.1", "lib")
62
+ gem_bin_path = File.join(@gem_dir, "gems", "gem_with_lib-0.0.1", "bin")
63
+ $LOAD_PATH.should_not include(gem_lib_path)
64
+ gem("gem_with_lib", "0.0.1").should be_true
65
+ $LOAD_PATH.first.should == gem_bin_path
66
+ $LOAD_PATH.should include(gem_lib_path)
67
+ end
68
+
69
+ it "uses 'gem' to setup additional load path entries (for a gem version requirement)" do
70
+ gem_lib_path = File.join(@gem_dir, "gems", "gem_with_lib-0.0.2", "lib")
71
+ gem_bin_path = File.join(@gem_dir, "gems", "gem_with_lib-0.0.2", "bin")
72
+ $LOAD_PATH.should_not include(gem_lib_path)
73
+ gem("gem_with_lib", ">0.0.1").should be_true
74
+ $LOAD_PATH.first.should == gem_bin_path
75
+ $LOAD_PATH.should include(gem_lib_path)
76
+ end
77
+
78
+ it "correctly requires a file from the load path" do
79
+ gem("gem_with_lib").should be_true
80
+ require("gem_with_lib").should be_true
81
+ lambda { GemWithLib::Awesome }.should_not raise_error(NameError)
82
+ GemWithLib::VERSION.should == "0.0.2"
83
+ end
84
+
85
+ it "returns all the latest gem versions' paths" do
86
+ Gem.latest_gem_paths.should == [File.join(@gem_dir, "gems", "gem_with_lib-0.0.2")]
87
+ end
88
+
89
+ # The following specs can only be run in isolation as they load up the
90
+ # full rubygems library - which cannot really be undone!
91
+ # Comment out the specs above, including before/after setup.
92
+
93
+ # it "should load full rubygems if an unimplemented method is called" do
94
+ # Gem.should be_minigems
95
+ # lambda { Gem.source_index }.should_not raise_error(NoMethodError)
96
+ # Gem.should_not be_minigems
97
+ # end
98
+
99
+ # it "should load full rubygems if a missing Gem constant is referenced" do
100
+ # Gem.should be_minigems
101
+ # lambda { Gem::Builder }.should_not raise_error(NameError)
102
+ # Gem.should_not be_minigems
103
+ # end
104
+
105
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minigems
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Fabien Franzen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-09-19 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Lighweight drop-in replacement for rubygems.
17
+ email: info@atelierfabien.be
18
+ executables:
19
+ - minigem
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - LICENSE
25
+ files:
26
+ - LICENSE
27
+ - README
28
+ - Rakefile
29
+ - lib/minigems
30
+ - lib/minigems/executable_wrapper
31
+ - lib/minigems/script_helper.rb
32
+ - lib/minigems.rb
33
+ - bin/minigem
34
+ - spec/fixtures
35
+ - spec/fixtures/cache
36
+ - spec/fixtures/cache/gem_with_lib-0.0.1.gem
37
+ - spec/fixtures/cache/gem_with_lib-0.0.2.gem
38
+ - spec/fixtures/gems
39
+ - spec/fixtures/gems/gem_with_lib-0.0.1
40
+ - spec/fixtures/gems/gem_with_lib-0.0.1/lib
41
+ - spec/fixtures/gems/gem_with_lib-0.0.1/lib/gem_with_lib.rb
42
+ - spec/fixtures/gems/gem_with_lib-0.0.1/LICENSE
43
+ - spec/fixtures/gems/gem_with_lib-0.0.1/Rakefile
44
+ - spec/fixtures/gems/gem_with_lib-0.0.1/README
45
+ - spec/fixtures/gems/gem_with_lib-0.0.1/TODO
46
+ - spec/fixtures/gems/gem_with_lib-0.0.2
47
+ - spec/fixtures/gems/gem_with_lib-0.0.2/bin
48
+ - spec/fixtures/gems/gem_with_lib-0.0.2/bin/gem_with_lib
49
+ - spec/fixtures/gems/gem_with_lib-0.0.2/lib
50
+ - spec/fixtures/gems/gem_with_lib-0.0.2/lib/gem_with_lib.rb
51
+ - spec/fixtures/gems/gem_with_lib-0.0.2/LICENSE
52
+ - spec/fixtures/gems/gem_with_lib-0.0.2/Rakefile
53
+ - spec/fixtures/gems/gem_with_lib-0.0.2/README
54
+ - spec/fixtures/gems/gem_with_lib-0.0.2/TODO
55
+ - spec/fixtures/specifications
56
+ - spec/fixtures/specifications/gem_with_lib-0.0.1.gemspec
57
+ - spec/fixtures/specifications/gem_with_lib-0.0.2.gemspec
58
+ - spec/minigems_spec.rb
59
+ has_rdoc: true
60
+ homepage: http://merbivore.com
61
+ minigems: false
62
+ post_install_message: Run 'minigem' for instructions on how to proceed.
63
+ rdoc_options: []
64
+
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project: merb
82
+ rubygems_version: 1.2.0.1874
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: Lighweight drop-in replacement for rubygems.
86
+ test_files: []
87
+