module Rubinjam

Constants

ROOT
VERSION

Public Class Methods

file_from_nesting(mod, const) click to toggle source
# File lib/rubinjam/internal.rb, line 14
def file_from_nesting(mod, const)
  if file = mod.rubinjam_autload[const]
    return [mod, file]
  end

  nesting(mod.name)[1..-1].detect do |mod|
    file = mod.rubinjam_autload[const]
    break [mod, file] if file
  end
end
nesting(name) click to toggle source

this does not reflect the actual Module.nesting of the caller, but it should be close enough

# File lib/rubinjam/internal.rb, line 27
def nesting(name)
  nesting = []
  namespace = name.split("::")
  namespace.inject(Object) do |base, n|
    klass = base.const_get(n)
    nesting << klass
    klass
  end
  nesting.reverse
end
normalize_file(file) click to toggle source
# File lib/rubinjam/internal.rb, line 5
def normalize_file(file)
  return file unless file.start_with?("/")
  if file.start_with?(ROOT)
    file.sub(ROOT, "")
  else
    file.split('/lib/').last
  end
end
pack(dir) click to toggle source

pack a directory

# File lib/rubinjam.rb, line 19
def pack(dir)
  Dir.chdir(dir) do
    binary = binary_path
    content = environment + File.read(binary)
    return [File.basename(binary), content]
  end
end
pack_gem(gem, version=nil) click to toggle source

pack a gem

# File lib/rubinjam.rb, line 28
def pack_gem(gem, version=nil)
  require "shellwords"
  require "rubygems/package"

  Dir.mktmpdir do |dir|
    Dir.chdir(dir) do
      # fetch
      command = "gem fetch #{Shellwords.escape(gem)}"
      command << " -v" << Shellwords.escape(version) if version
      sh(command)

      # load spec
      gem_ball = Dir["*.gem"].first
      spec = Gem::Package.new(gem_ball).spec.to_ruby
      sh("gem unpack #{Shellwords.escape(gem_ball)}")

      # bundle
      Dir.chdir(gem_ball.sub(".gem", "")) do
        write_file "#{gem}.gemspec", spec
        Rubinjam.pack(Dir.pwd)
      end
    end
  end
end
write(dir) click to toggle source

pack and write a binary given a directory

# File lib/rubinjam.rb, line 10
def write(dir)
  name, content = pack(Dir.pwd)
  write_file name, content
  `chmod +x #{name}`
  raise "Unable to add execution bit" unless $?.success?
  name
end

Private Class Methods

binary_path() click to toggle source
# File lib/rubinjam.rb, line 55
def binary_path
  folders = ["./exe", "./bin"]
  folders.each do |folder|
    binaries = Dir["#{folder}/*"]
    next if binaries.size == 0
    if binaries.size != 1
      local = File.join(folder, File.basename(Dir.pwd))
      if binaries.include?(local)
        binaries = [local]
      else
        raise "Can only pack exactly 1 binary, found #{binaries.join(", ")} in #{folder}"
      end
    end
    return binaries.first
  end
  raise "No binary found in #{folders.join(" or ")}"
end
environment() click to toggle source
# File lib/rubinjam.rb, line 135
    def environment
      <<-RUBY.gsub(/^        /, "")
        #{HEADER}
        # generated by rubinjam v#{VERSION} -- https://github.com/grosser/rubinjam
        module Rubinjam
          LIBRARIES = {
            #{libraries.map { |name,content| "#{name.inspect} => #{content.inspect}" }.join(",\n    ")}
          }
        end
        eval(Rubinjam::LIBRARIES.fetch("rubinjam/internal"), TOPLEVEL_BINDING, "rubinjam")
      RUBY
    end
gem_libraries() click to toggle source

unpack dependent gems with bundler so we can pack them this takes a while so we try to avoid if possible

# File lib/rubinjam.rb, line 89
    def gem_libraries
      return {} unless gemspec = Dir["*.gemspec"].first

      dependency = "add_(runtime_)?dependency"
      content = File.read(gemspec)
      content.gsub!(/.*#{dependency}.*['"\{\<]json['">\}].*/, '')
      content.gsub!(/.*add_development_dependency.*/, "")
      return {} unless content =~ /#{dependency}/

      Dir.mktmpdir do |dir|
        sh "cp -R . #{dir}/"
        Dir.chdir(dir) do
          write_file gemspec, content
          write_file "Gemfile", <<-RUBY.gsub(/^            /, "")
            source "https://rubygems.org"
            gemspec
          RUBY

          sh("rm -f Gemfile.lock")
          sh("BUNDLE_IGNORE_CONFIG=1 bundle install --quiet --path bundle") # heroku has a --deployment config -> ignore it
          paths = sh("bundle exec ruby -e 'puts $LOAD_PATH'").split("\n")
          paths = paths.grep(%r{/gems/}).reject { |r| r =~ %r{/gems/bundler-\d} }
          libs_from_paths(paths)
        end
      end
    end
internal_code() click to toggle source
# File lib/rubinjam.rb, line 79
def internal_code
  if defined?(LIBRARIES)
    LIBRARIES["rubinjam/internal"] # dogfooding ourself -> cannot reed files
  else
    File.read(File.expand_path("../rubinjam/internal.rb", __FILE__))
  end
end
libraries() click to toggle source
# File lib/rubinjam.rb, line 73
def libraries
  libs_from_paths(["lib"]).
    merge!(gem_libraries).
    merge!("rubinjam/internal" => internal_code)
end
libs_from_paths(paths) click to toggle source
# File lib/rubinjam.rb, line 116
def libs_from_paths(paths)
  paths.select { |p| File.directory?(p) }.inject({}) do |all, path|
    Dir.chdir path do
      all.merge!(Hash[Dir["**/*.rb"].map { |f| [f.sub(/\.rb$/, ""), File.read(f)] }])
    end
  end
end
sh(command, options={}) click to toggle source
# File lib/rubinjam.rb, line 124
def sh(command, options={})
  result = Bundler.with_clean_env { `#{command} 2>/dev/null` }
  raise "#{options[:fail] ? "SUCCESS" : "FAIL"} #{command}\n#{result}" if $?.success? == !!options[:fail]
  result
end
write_file(file, content) click to toggle source
# File lib/rubinjam.rb, line 130
def write_file(file, content)
  FileUtils.mkdir_p(File.dirname(file))
  File.open(file, "w") { |f| f.write content }
end