diff --git a/History.txt b/History similarity index 100% rename from History.txt rename to History diff --git a/License.txt b/License similarity index 100% rename from License.txt rename to License diff --git a/Manifest.txt b/Manifest similarity index 88% rename from Manifest.txt rename to Manifest index 614799b36..12687fb21 100644 --- a/Manifest.txt +++ b/Manifest @@ -1,11 +1,4 @@ -History.txt -License.txt -Manifest.txt -README.txt -Rakefile bin/twitter -config/hoe.rb -config/requirements.rb examples/blocks.rb examples/direct_messages.rb examples/favorites.rb @@ -20,9 +13,8 @@ examples/sent_messages.rb examples/timeline.rb examples/twitter.rb examples/verify_credentials.rb -lib/twitter.rb +History lib/twitter/base.rb -lib/twitter/cli.rb lib/twitter/cli/config.rb lib/twitter/cli/helpers.rb lib/twitter/cli/migrations/20080722194500_create_accounts.rb @@ -32,6 +24,7 @@ lib/twitter/cli/migrations/20080722214606_create_configurations.rb lib/twitter/cli/models/account.rb lib/twitter/cli/models/configuration.rb lib/twitter/cli/models/tweet.rb +lib/twitter/cli.rb lib/twitter/direct_message.rb lib/twitter/easy_class_maker.rb lib/twitter/rate_limit_status.rb @@ -39,10 +32,11 @@ lib/twitter/search.rb lib/twitter/status.rb lib/twitter/user.rb lib/twitter/version.rb -script/destroy -script/generate -script/txt2html -setup.rb +lib/twitter.rb +License +Manifest +Rakefile +README spec/base_spec.rb spec/cli/helper_spec.rb spec/direct_message_spec.rb @@ -62,9 +56,6 @@ spec/spec.opts spec/spec_helper.rb spec/status_spec.rb spec/user_spec.rb -tasks/deployment.rake -tasks/environment.rake -tasks/website.rake twitter.gemspec website/css/common.css website/images/terminal_output.png diff --git a/README.txt b/README similarity index 100% rename from README.txt rename to README diff --git a/Rakefile b/Rakefile index e469154c2..0df62f26c 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,42 @@ -require 'config/requirements' -require 'config/hoe' # setup Hoe + all gem configuration +ProjectName = 'twitter' +WebsitePath = "jnunemaker@rubyforge.org:/var/www/gforge-projects/#{ProjectName}" -Dir['tasks/**/*.rake'].each { |rake| load rake } \ No newline at end of file +require 'rubygems' +require 'rake' +require 'echoe' +require 'spec/rake/spectask' +require "lib/#{ProjectName}/version" + +Echoe.new(ProjectName, Twitter::Version) do |p| + p.description = "a command line interface for twitter, also a library which wraps the twitter api" + p.url = "http://#{ProjectName}.rubyforge.org" + p.author = "John Nunemaker" + p.email = "nunemaker@gmail.com" + p.extra_deps = [['hpricot', '>= 0.6'], ['activesupport', '>= 2.1'], ['httparty', '>= 0.2.4']] + p.need_tar_gz = false + p.docs_host = WebsitePath +end + +desc 'Upload website files to rubyforge' +task :website do + sh %{rsync -av website/ #{WebsitePath}} + Rake::Task['website_docs'].invoke +end + +task :website_docs do + Rake::Task['redocs'].invoke + sh %{rsync -av doc/ #{WebsitePath}/docs} +end + +desc 'Preps the gem for a new release' +task :prepare do + %w[manifest build_gemspec].each do |task| + Rake::Task[task].invoke + end +end + +Rake::Task[:default].prerequisites.clear +task :default => :spec +Spec::Rake::SpecTask.new do |t| + t.spec_files = FileList["spec/**/*_spec.rb"] +end \ No newline at end of file diff --git a/bin/twitter b/bin/twitter index 9d0634e71..3816b2950 100644 --- a/bin/twitter +++ b/bin/twitter @@ -10,11 +10,5 @@ if ARGV[0] && ARGV[0] == 'd' && !STDIN.tty? ARGV[2] = "#{STDIN.read}#{ARGV[2]}" end -require 'rubygems' - -gem 'main', '>= 2.8.2' -gem 'highline', '>= 1.4.0' -gem 'activerecord', '>= 2.1' - -require 'twitter' +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')) require 'twitter/cli' \ No newline at end of file diff --git a/config/hoe.rb b/config/hoe.rb deleted file mode 100644 index a4282247a..000000000 --- a/config/hoe.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'twitter/version' - -AUTHOR = "John Nunemaker" # can also be an array of Authors -EMAIL = "nunemaker@gmail.com" -DESCRIPTION = "a command line interface for twitter, also a library which wraps the twitter api" -GEM_NAME = "twitter" # what ppl will type to install your gem -RUBYFORGE_PROJECT = "twitter" # The unix name for your project -HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org" -RELEASE_TYPES = %w( gem ) # can use: gem, tar, zip -DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" - -@config_file = "~/.rubyforge/user-config.yml" -@config = nil -RUBYFORGE_USERNAME = "unknown" -def rubyforge_username - unless @config - begin - @config = YAML.load(File.read(File.expand_path(@config_file))) - rescue - puts <<-EOS -ERROR: No rubyforge config file found: #{@config_file} -Run 'rubyforge setup' to prepare your env for access to Rubyforge - - See http://newgem.rubyforge.org/rubyforge.html for more details - EOS - exit - end - end - RUBYFORGE_USERNAME.replace @config["username"] -end - - -REV = nil -# UNCOMMENT IF REQUIRED: -# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil -VERS = Twitter::VERSION::STRING + (REV ? ".#{REV}" : "") -RDOC_OPTS = ['--quiet', '--title', 'twitter documentation', - "--opname", "index.html", - "--line-numbers", - "--main", "README", - "--inline-source"] - -class Hoe - def extra_deps - @extra_deps.reject! { |x| Array(x).first == 'hoe' } - @extra_deps - end -end - -# Generate all the Rake tasks -# Run 'rake -T' to see list of generated tasks (from gem root directory) -hoe = Hoe.new(GEM_NAME, VERS) do |p| - p.author = AUTHOR - p.description = DESCRIPTION - p.email = EMAIL - p.summary = DESCRIPTION - p.url = HOMEPATH - p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT - p.test_globs = ["test/**/test_*.rb"] - p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean. - - # == Optional - p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n") - #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ] - p.extra_deps = [['hpricot', '>= 0.6'], ['activesupport', '>= 2.1'], ['httparty', '>= 0.2.4']] - #p.spec_extras = {} # A hash of extra values to set in the gemspec. - -end - -CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n") -PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}" -hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc') -hoe.rsync_args = '-av --delete --ignore-errors' \ No newline at end of file diff --git a/config/requirements.rb b/config/requirements.rb deleted file mode 100644 index eaba03d01..000000000 --- a/config/requirements.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'fileutils' -include FileUtils - -require 'rubygems' -%w[rake hoe newgem rubigen].each do |req_gem| - begin - require req_gem - rescue LoadError - puts "This Rakefile requires the '#{req_gem}' RubyGem." - puts "Installation: gem install #{req_gem} -y" - exit - end -end - -$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib])) - -require 'twitter' \ No newline at end of file diff --git a/lib/twitter.rb b/lib/twitter.rb index fed4d92f7..d9bcc6014 100644 --- a/lib/twitter.rb +++ b/lib/twitter.rb @@ -1,6 +1,12 @@ -%w(uri cgi net/http yaml rubygems hpricot active_support).each { |f| require f } +require 'uri' +require 'cgi' +require 'net/http' +require 'yaml' +require 'time' +require 'rubygems' +require 'hpricot' -$:.unshift(File.join(File.dirname(__FILE__))) +$:.unshift(File.dirname(__FILE__)) require 'twitter/version' require 'twitter/easy_class_maker' require 'twitter/base' diff --git a/lib/twitter/base.rb b/lib/twitter/base.rb index 591c9ba3e..de2a872bf 100644 --- a/lib/twitter/base.rb +++ b/lib/twitter/base.rb @@ -184,7 +184,7 @@ def users(doc) # # ie: call(:public_timeline, :auth => false) def call(method, options={}) - options.reverse_merge!({ :auth => true, :args => {} }) + options = { :auth => true, :args => {} }.merge(options) # Following line needed as lite=false doesn't work in the API: http://tinyurl.com/yo3h5d options[:args].delete(:lite) unless options[:args][:lite] args = options.delete(:args) @@ -193,11 +193,12 @@ def call(method, options={}) # Makes a request to twitter. def request(path, options={}) - options.reverse_merge!({ + options = { :headers => { "User-Agent" => @config[:email] }, - :method => :get - }) - unless options[:since].blank? + :method => :get, + }.merge(options) + + unless options[:since].nil? since = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s options[:headers]["If-Modified-Since"] = since end @@ -233,7 +234,11 @@ def request(path, options={}) # Given a path and a hash, build a full path with the hash turned into a query string def build_path(path, options) - path += "?#{options.to_query}" unless options.blank? + unless options.nil? + query = options.inject('') { |str, h| str += "#{CGI.escape(h[0].to_s)}=#{CGI.escape(h[1].to_s)}&"; str } + path += "?#{query}" + end + path end diff --git a/lib/twitter/cli.rb b/lib/twitter/cli.rb index 36a6cf4d1..a651445d0 100644 --- a/lib/twitter/cli.rb +++ b/lib/twitter/cli.rb @@ -1,8 +1,10 @@ require 'rubygems' + gem 'main', '>= 2.8.2' gem 'highline', '>= 1.4.0' gem 'activerecord', '>= 2.1' gem 'sqlite3-ruby', '>= 1.2.1' + require 'main' require 'highline/import' require 'activerecord' @@ -280,7 +282,7 @@ def run do_work do timeline = params['timeline'].value == 'me' ? 'user' : params['timeline'].value options, since_id = {}, Configuration["#{timeline}_since_id"] - options[:since_id] = since_id if !since_id.blank? && !params['force'].given? + options[:since_id] = since_id if !since_id.nil? && !params['force'].given? cache = [:friends, :user].include?(timeline) collection = base.timeline(timeline.to_sym, options) output_tweets(collection, {:cache => cache, :since_prefix => timeline}) @@ -297,7 +299,7 @@ def run def run do_work do options, since_id = {}, Configuration["replies_since_id"] - options[:since_id] = since_id if !since_id.blank? && !params['force'].given? + options[:since_id] = since_id if !since_id.nil? && !params['force'].given? collection = base.replies(options) output_tweets(collection, {:since_prefix => 'replies'}) end diff --git a/lib/twitter/cli/helpers.rb b/lib/twitter/cli/helpers.rb index 96dc3031a..ef99af2aa 100644 --- a/lib/twitter/cli/helpers.rb +++ b/lib/twitter/cli/helpers.rb @@ -5,24 +5,34 @@ class NoActiveAccount < StandardError; end class NoAccounts < StandardError; end def output_tweets(collection, options={}) - options.reverse_merge!({ + options = { :cache => false, :since_prefix => '', :empty_msg => 'Nothing new since your last check.' - }) + }.merge(options) + if collection.size > 0 justify = collection.collect { |s| s.user.screen_name }.max { |a,b| a.length <=> b.length }.length rescue 0 indention = ' ' * (justify + 3) say("\n#{indention}#{collection.size} new tweet(s) found.\n\n") collection.each do |s| Tweet.create_from_tweet(current_account, s) if options[:cache] + occurred_at = Time.parse(s.created_at).strftime('On %b %d at %l:%M%P') formatted_time = '-' * occurred_at.length + "\n#{indention}#{occurred_at}" formatted_name = s.user.screen_name.rjust(justify + 1) formatted_msg = '' - s.text.split(' ').in_groups_of(6, false) { |row| formatted_msg += row.join(' ') + "\n#{indention}" } - say "#{CGI::unescapeHTML(formatted_name)}: #{CGI::unescapeHTML(formatted_msg)}#{formatted_time}\n\n" + + s.text.split(' ').each_with_index do |word, idx| + formatted_msg += "#{word} " + + sixth_word = idx != 0 && idx % 6 == 0 + formatted_msg += "\n#{indention}" if sixth_word + end + + say "#{CGI::unescapeHTML(formatted_name)}: #{CGI::unescapeHTML(formatted_msg)}\n#{indention}#{formatted_time}\n\n" end + Configuration["#{options[:since_prefix]}_since_id"] = collection.first.id else say(options[:empty_msg]) @@ -35,7 +45,7 @@ def base(username=current_account.username, password=current_account.password) def current_account @current_account ||= Account.active - raise Account.count == 0 ? NoAccounts : NoActiveAccount if @current_account.blank? + raise Account.count == 0 ? NoAccounts : NoActiveAccount if @current_account.nil? @current_account end @@ -44,7 +54,7 @@ def attempt_import(&block) if File.exists?(tweet_file) say '.twitter file found, attempting import...' config = YAML::load(File.read(tweet_file)) - if !config['email'].blank? && !config['password'].blank? + if !config['email'].nil? && !config['password'].nil? Account.add(:username => config['email'], :password => config['password']) say 'Account imported' block.call if block_given? diff --git a/lib/twitter/search.rb b/lib/twitter/search.rb index 4acaf3ef0..fe4c16c1e 100644 --- a/lib/twitter/search.rb +++ b/lib/twitter/search.rb @@ -11,7 +11,7 @@ class Search def initialize(q=nil) clear - containing(q) unless q.blank? + containing(q) if q && q.strip != '' end def from(user) diff --git a/lib/twitter/version.rb b/lib/twitter/version.rb index d6338f27e..a832b3469 100644 --- a/lib/twitter/version.rb +++ b/lib/twitter/version.rb @@ -1,9 +1,3 @@ module Twitter #:nodoc: - module VERSION #:nodoc: - MAJOR = 0 - MINOR = 3 - TINY = 8 - - STRING = [MAJOR, MINOR, TINY].join('.') - end + Version = '0.4.0' end \ No newline at end of file diff --git a/log/debug.log b/log/debug.log deleted file mode 100644 index e69de29bb..000000000 diff --git a/script/destroy b/script/destroy deleted file mode 100755 index 5fa7e10e7..000000000 --- a/script/destroy +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby -APP_ROOT = File.join(File.dirname(__FILE__), '..') - -begin - require 'rubigen' -rescue LoadError - require 'rubygems' - require 'rubigen' -end -require 'rubigen/scripts/destroy' - -ARGV.shift if ['--help', '-h'].include?(ARGV[0]) -RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit] -RubiGen::Scripts::Destroy.new.run(ARGV) diff --git a/script/generate b/script/generate deleted file mode 100755 index 230a18685..000000000 --- a/script/generate +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby -APP_ROOT = File.join(File.dirname(__FILE__), '..') - -begin - require 'rubigen' -rescue LoadError - require 'rubygems' - require 'rubigen' -end -require 'rubigen/scripts/generate' - -ARGV.shift if ['--help', '-h'].include?(ARGV[0]) -RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit] -RubiGen::Scripts::Generate.new.run(ARGV) diff --git a/script/txt2html b/script/txt2html deleted file mode 100755 index e3359fda2..000000000 --- a/script/txt2html +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -begin - require 'newgem' -rescue LoadError - puts "\n\nGenerating the website requires the newgem RubyGem" - puts "Install: gem install newgem\n\n" - exit(1) -end -require 'redcloth' -require 'syntax/convertors/html' -require 'erb' -require File.dirname(__FILE__) + '/../lib/twitter/version.rb' - -version = Twitter.git::VERSION::STRING -download = 'http://rubyforge.org/projects/twitter' - -class Fixnum - def ordinal - # teens - return 'th' if (10..19).include?(self % 100) - # others - case self % 10 - when 1: return 'st' - when 2: return 'nd' - when 3: return 'rd' - else return 'th' - end - end -end - -class Time - def pretty - return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}" - end -end - -def convert_syntax(syntax, source) - return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^
|$!,'') -end - -if ARGV.length >= 1 - src, template = ARGV - template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml') - -else - puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html") - exit! -end - -template = ERB.new(File.open(template).read) - -title = nil -body = nil -File.open(src) do |fsrc| - title_text = fsrc.readline - body_text = fsrc.read - syntax_items = [] - body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)\1>!m){ - ident = syntax_items.length - element, syntax, source = $1, $2, $3 - syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}#{element}>" - "syntax-temp-#{ident}" - } - title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip - body = RedCloth.new(body_text).to_html - body.gsub!(%r!(?:
)?syntax-temp-(\d+)(?:
)?!){ syntax_items[$1.to_i] }
-end
-stat = File.stat(src)
-created = stat.ctime
-modified = stat.mtime
-
-$stdout << template.result(binding)
diff --git a/setup.rb b/setup.rb
deleted file mode 100644
index 424a5f37c..000000000
--- a/setup.rb
+++ /dev/null
@@ -1,1585 +0,0 @@
-#
-# setup.rb
-#
-# Copyright (c) 2000-2005 Minero Aoki
-#
-# This program is free software.
-# You can distribute/modify this program under the terms of
-# the GNU LGPL, Lesser General Public License version 2.1.
-#
-
-unless Enumerable.method_defined?(:map) # Ruby 1.4.6
- module Enumerable
- alias map collect
- end
-end
-
-unless File.respond_to?(:read) # Ruby 1.6
- def File.read(fname)
- open(fname) {|f|
- return f.read
- }
- end
-end
-
-unless Errno.const_defined?(:ENOTEMPTY) # Windows?
- module Errno
- class ENOTEMPTY
- # We do not raise this exception, implementation is not needed.
- end
- end
-end
-
-def File.binread(fname)
- open(fname, 'rb') {|f|
- return f.read
- }
-end
-
-# for corrupted Windows' stat(2)
-def File.dir?(path)
- File.directory?((path[-1,1] == '/') ? path : path + '/')
-end
-
-
-class ConfigTable
-
- include Enumerable
-
- def initialize(rbconfig)
- @rbconfig = rbconfig
- @items = []
- @table = {}
- # options
- @install_prefix = nil
- @config_opt = nil
- @verbose = true
- @no_harm = false
- end
-
- attr_accessor :install_prefix
- attr_accessor :config_opt
-
- attr_writer :verbose
-
- def verbose?
- @verbose
- end
-
- attr_writer :no_harm
-
- def no_harm?
- @no_harm
- end
-
- def [](key)
- lookup(key).resolve(self)
- end
-
- def []=(key, val)
- lookup(key).set val
- end
-
- def names
- @items.map {|i| i.name }
- end
-
- def each(&block)
- @items.each(&block)
- end
-
- def key?(name)
- @table.key?(name)
- end
-
- def lookup(name)
- @table[name] or setup_rb_error "no such config item: #{name}"
- end
-
- def add(item)
- @items.push item
- @table[item.name] = item
- end
-
- def remove(name)
- item = lookup(name)
- @items.delete_if {|i| i.name == name }
- @table.delete_if {|name, i| i.name == name }
- item
- end
-
- def load_script(path, inst = nil)
- if File.file?(path)
- MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
- end
- end
-
- def savefile
- '.config'
- end
-
- def load_savefile
- begin
- File.foreach(savefile()) do |line|
- k, v = *line.split(/=/, 2)
- self[k] = v.strip
- end
- rescue Errno::ENOENT
- setup_rb_error $!.message + "\n#{File.basename($0)} config first"
- end
- end
-
- def save
- @items.each {|i| i.value }
- File.open(savefile(), 'w') {|f|
- @items.each do |i|
- f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
- end
- }
- end
-
- def load_standard_entries
- standard_entries(@rbconfig).each do |ent|
- add ent
- end
- end
-
- def standard_entries(rbconfig)
- c = rbconfig
-
- rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
-
- major = c['MAJOR'].to_i
- minor = c['MINOR'].to_i
- teeny = c['TEENY'].to_i
- version = "#{major}.#{minor}"
-
- # ruby ver. >= 1.4.4?
- newpath_p = ((major >= 2) or
- ((major == 1) and
- ((minor >= 5) or
- ((minor == 4) and (teeny >= 4)))))
-
- if c['rubylibdir']
- # V > 1.6.3
- libruby = "#{c['prefix']}/lib/ruby"
- librubyver = c['rubylibdir']
- librubyverarch = c['archdir']
- siteruby = c['sitedir']
- siterubyver = c['sitelibdir']
- siterubyverarch = c['sitearchdir']
- elsif newpath_p
- # 1.4.4 <= V <= 1.6.3
- libruby = "#{c['prefix']}/lib/ruby"
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
- siteruby = c['sitedir']
- siterubyver = "$siteruby/#{version}"
- siterubyverarch = "$siterubyver/#{c['arch']}"
- else
- # V < 1.4.4
- libruby = "#{c['prefix']}/lib/ruby"
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
- siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
- siterubyver = siteruby
- siterubyverarch = "$siterubyver/#{c['arch']}"
- end
- parameterize = lambda {|path|
- path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
- }
-
- if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
- makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
- else
- makeprog = 'make'
- end
-
- [
- ExecItem.new('installdirs', 'std/site/home',
- 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
- {|val, table|
- case val
- when 'std'
- table['rbdir'] = '$librubyver'
- table['sodir'] = '$librubyverarch'
- when 'site'
- table['rbdir'] = '$siterubyver'
- table['sodir'] = '$siterubyverarch'
- when 'home'
- setup_rb_error '$HOME was not set' unless ENV['HOME']
- table['prefix'] = ENV['HOME']
- table['rbdir'] = '$libdir/ruby'
- table['sodir'] = '$libdir/ruby'
- end
- },
- PathItem.new('prefix', 'path', c['prefix'],
- 'path prefix of target environment'),
- PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
- 'the directory for commands'),
- PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
- 'the directory for libraries'),
- PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
- 'the directory for shared data'),
- PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
- 'the directory for man pages'),
- PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
- 'the directory for system configuration files'),
- PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
- 'the directory for local state data'),
- PathItem.new('libruby', 'path', libruby,
- 'the directory for ruby libraries'),
- PathItem.new('librubyver', 'path', librubyver,
- 'the directory for standard ruby libraries'),
- PathItem.new('librubyverarch', 'path', librubyverarch,
- 'the directory for standard ruby extensions'),
- PathItem.new('siteruby', 'path', siteruby,
- 'the directory for version-independent aux ruby libraries'),
- PathItem.new('siterubyver', 'path', siterubyver,
- 'the directory for aux ruby libraries'),
- PathItem.new('siterubyverarch', 'path', siterubyverarch,
- 'the directory for aux ruby binaries'),
- PathItem.new('rbdir', 'path', '$siterubyver',
- 'the directory for ruby scripts'),
- PathItem.new('sodir', 'path', '$siterubyverarch',
- 'the directory for ruby extentions'),
- PathItem.new('rubypath', 'path', rubypath,
- 'the path to set to #! line'),
- ProgramItem.new('rubyprog', 'name', rubypath,
- 'the ruby program using for installation'),
- ProgramItem.new('makeprog', 'name', makeprog,
- 'the make program to compile ruby extentions'),
- SelectItem.new('shebang', 'all/ruby/never', 'ruby',
- 'shebang line (#!) editing mode'),
- BoolItem.new('without-ext', 'yes/no', 'no',
- 'does not compile/install ruby extentions')
- ]
- end
- private :standard_entries
-
- def load_multipackage_entries
- multipackage_entries().each do |ent|
- add ent
- end
- end
-
- def multipackage_entries
- [
- PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
- 'package names that you want to install'),
- PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
- 'package names that you do not want to install')
- ]
- end
- private :multipackage_entries
-
- ALIASES = {
- 'std-ruby' => 'librubyver',
- 'stdruby' => 'librubyver',
- 'rubylibdir' => 'librubyver',
- 'archdir' => 'librubyverarch',
- 'site-ruby-common' => 'siteruby', # For backward compatibility
- 'site-ruby' => 'siterubyver', # For backward compatibility
- 'bin-dir' => 'bindir',
- 'bin-dir' => 'bindir',
- 'rb-dir' => 'rbdir',
- 'so-dir' => 'sodir',
- 'data-dir' => 'datadir',
- 'ruby-path' => 'rubypath',
- 'ruby-prog' => 'rubyprog',
- 'ruby' => 'rubyprog',
- 'make-prog' => 'makeprog',
- 'make' => 'makeprog'
- }
-
- def fixup
- ALIASES.each do |ali, name|
- @table[ali] = @table[name]
- end
- @items.freeze
- @table.freeze
- @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
- end
-
- def parse_opt(opt)
- m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
- m.to_a[1,2]
- end
-
- def dllext
- @rbconfig['DLEXT']
- end
-
- def value_config?(name)
- lookup(name).value?
- end
-
- class Item
- def initialize(name, template, default, desc)
- @name = name.freeze
- @template = template
- @value = default
- @default = default
- @description = desc
- end
-
- attr_reader :name
- attr_reader :description
-
- attr_accessor :default
- alias help_default default
-
- def help_opt
- "--#{@name}=#{@template}"
- end
-
- def value?
- true
- end
-
- def value
- @value
- end
-
- def resolve(table)
- @value.gsub(%r<\$([^/]+)>) { table[$1] }
- end
-
- def set(val)
- @value = check(val)
- end
-
- private
-
- def check(val)
- setup_rb_error "config: --#{name} requires argument" unless val
- val
- end
- end
-
- class BoolItem < Item
- def config_type
- 'bool'
- end
-
- def help_opt
- "--#{@name}"
- end
-
- private
-
- def check(val)
- return 'yes' unless val
- case val
- when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
- when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
- else
- setup_rb_error "config: --#{@name} accepts only yes/no for argument"
- end
- end
- end
-
- class PathItem < Item
- def config_type
- 'path'
- end
-
- private
-
- def check(path)
- setup_rb_error "config: --#{@name} requires argument" unless path
- path[0,1] == '$' ? path : File.expand_path(path)
- end
- end
-
- class ProgramItem < Item
- def config_type
- 'program'
- end
- end
-
- class SelectItem < Item
- def initialize(name, selection, default, desc)
- super
- @ok = selection.split('/')
- end
-
- def config_type
- 'select'
- end
-
- private
-
- def check(val)
- unless @ok.include?(val.strip)
- setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
- end
- val.strip
- end
- end
-
- class ExecItem < Item
- def initialize(name, selection, desc, &block)
- super name, selection, nil, desc
- @ok = selection.split('/')
- @action = block
- end
-
- def config_type
- 'exec'
- end
-
- def value?
- false
- end
-
- def resolve(table)
- setup_rb_error "$#{name()} wrongly used as option value"
- end
-
- undef set
-
- def evaluate(val, table)
- v = val.strip.downcase
- unless @ok.include?(v)
- setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
- end
- @action.call v, table
- end
- end
-
- class PackageSelectionItem < Item
- def initialize(name, template, default, help_default, desc)
- super name, template, default, desc
- @help_default = help_default
- end
-
- attr_reader :help_default
-
- def config_type
- 'package'
- end
-
- private
-
- def check(val)
- unless File.dir?("packages/#{val}")
- setup_rb_error "config: no such package: #{val}"
- end
- val
- end
- end
-
- class MetaConfigEnvironment
- def initialize(config, installer)
- @config = config
- @installer = installer
- end
-
- def config_names
- @config.names
- end
-
- def config?(name)
- @config.key?(name)
- end
-
- def bool_config?(name)
- @config.lookup(name).config_type == 'bool'
- end
-
- def path_config?(name)
- @config.lookup(name).config_type == 'path'
- end
-
- def value_config?(name)
- @config.lookup(name).config_type != 'exec'
- end
-
- def add_config(item)
- @config.add item
- end
-
- def add_bool_config(name, default, desc)
- @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
- end
-
- def add_path_config(name, default, desc)
- @config.add PathItem.new(name, 'path', default, desc)
- end
-
- def set_config_default(name, default)
- @config.lookup(name).default = default
- end
-
- def remove_config(name)
- @config.remove(name)
- end
-
- # For only multipackage
- def packages
- raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
- @installer.packages
- end
-
- # For only multipackage
- def declare_packages(list)
- raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
- @installer.packages = list
- end
- end
-
-end # class ConfigTable
-
-
-# This module requires: #verbose?, #no_harm?
-module FileOperations
-
- def mkdir_p(dirname, prefix = nil)
- dirname = prefix + File.expand_path(dirname) if prefix
- $stderr.puts "mkdir -p #{dirname}" if verbose?
- return if no_harm?
-
- # Does not check '/', it's too abnormal.
- dirs = File.expand_path(dirname).split(%r<(?=/)>)
- if /\A[a-z]:\z/i =~ dirs[0]
- disk = dirs.shift
- dirs[0] = disk + dirs[0]
- end
- dirs.each_index do |idx|
- path = dirs[0..idx].join('')
- Dir.mkdir path unless File.dir?(path)
- end
- end
-
- def rm_f(path)
- $stderr.puts "rm -f #{path}" if verbose?
- return if no_harm?
- force_remove_file path
- end
-
- def rm_rf(path)
- $stderr.puts "rm -rf #{path}" if verbose?
- return if no_harm?
- remove_tree path
- end
-
- def remove_tree(path)
- if File.symlink?(path)
- remove_file path
- elsif File.dir?(path)
- remove_tree0 path
- else
- force_remove_file path
- end
- end
-
- def remove_tree0(path)
- Dir.foreach(path) do |ent|
- next if ent == '.'
- next if ent == '..'
- entpath = "#{path}/#{ent}"
- if File.symlink?(entpath)
- remove_file entpath
- elsif File.dir?(entpath)
- remove_tree0 entpath
- else
- force_remove_file entpath
- end
- end
- begin
- Dir.rmdir path
- rescue Errno::ENOTEMPTY
- # directory may not be empty
- end
- end
-
- def move_file(src, dest)
- force_remove_file dest
- begin
- File.rename src, dest
- rescue
- File.open(dest, 'wb') {|f|
- f.write File.binread(src)
- }
- File.chmod File.stat(src).mode, dest
- File.unlink src
- end
- end
-
- def force_remove_file(path)
- begin
- remove_file path
- rescue
- end
- end
-
- def remove_file(path)
- File.chmod 0777, path
- File.unlink path
- end
-
- def install(from, dest, mode, prefix = nil)
- $stderr.puts "install #{from} #{dest}" if verbose?
- return if no_harm?
-
- realdest = prefix ? prefix + File.expand_path(dest) : dest
- realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
- str = File.binread(from)
- if diff?(str, realdest)
- verbose_off {
- rm_f realdest if File.exist?(realdest)
- }
- File.open(realdest, 'wb') {|f|
- f.write str
- }
- File.chmod mode, realdest
-
- File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
- if prefix
- f.puts realdest.sub(prefix, '')
- else
- f.puts realdest
- end
- }
- end
- end
-
- def diff?(new_content, path)
- return true unless File.exist?(path)
- new_content != File.binread(path)
- end
-
- def command(*args)
- $stderr.puts args.join(' ') if verbose?
- system(*args) or raise RuntimeError,
- "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
- end
-
- def ruby(*args)
- command config('rubyprog'), *args
- end
-
- def make(task = nil)
- command(*[config('makeprog'), task].compact)
- end
-
- def extdir?(dir)
- File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
- end
-
- def files_of(dir)
- Dir.open(dir) {|d|
- return d.select {|ent| File.file?("#{dir}/#{ent}") }
- }
- end
-
- DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
-
- def directories_of(dir)
- Dir.open(dir) {|d|
- return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
- }
- end
-
-end
-
-
-# This module requires: #srcdir_root, #objdir_root, #relpath
-module HookScriptAPI
-
- def get_config(key)
- @config[key]
- end
-
- alias config get_config
-
- # obsolete: use metaconfig to change configuration
- def set_config(key, val)
- @config[key] = val
- end
-
- #
- # srcdir/objdir (works only in the package directory)
- #
-
- def curr_srcdir
- "#{srcdir_root()}/#{relpath()}"
- end
-
- def curr_objdir
- "#{objdir_root()}/#{relpath()}"
- end
-
- def srcfile(path)
- "#{curr_srcdir()}/#{path}"
- end
-
- def srcexist?(path)
- File.exist?(srcfile(path))
- end
-
- def srcdirectory?(path)
- File.dir?(srcfile(path))
- end
-
- def srcfile?(path)
- File.file?(srcfile(path))
- end
-
- def srcentries(path = '.')
- Dir.open("#{curr_srcdir()}/#{path}") {|d|
- return d.to_a - %w(. ..)
- }
- end
-
- def srcfiles(path = '.')
- srcentries(path).select {|fname|
- File.file?(File.join(curr_srcdir(), path, fname))
- }
- end
-
- def srcdirectories(path = '.')
- srcentries(path).select {|fname|
- File.dir?(File.join(curr_srcdir(), path, fname))
- }
- end
-
-end
-
-
-class ToplevelInstaller
-
- Version = '3.4.1'
- Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
-
- TASKS = [
- [ 'all', 'do config, setup, then install' ],
- [ 'config', 'saves your configurations' ],
- [ 'show', 'shows current configuration' ],
- [ 'setup', 'compiles ruby extentions and others' ],
- [ 'install', 'installs files' ],
- [ 'test', 'run all tests in test/' ],
- [ 'clean', "does `make clean' for each extention" ],
- [ 'distclean',"does `make distclean' for each extention" ]
- ]
-
- def ToplevelInstaller.invoke
- config = ConfigTable.new(load_rbconfig())
- config.load_standard_entries
- config.load_multipackage_entries if multipackage?
- config.fixup
- klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
- klass.new(File.dirname($0), config).invoke
- end
-
- def ToplevelInstaller.multipackage?
- File.dir?(File.dirname($0) + '/packages')
- end
-
- def ToplevelInstaller.load_rbconfig
- if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
- ARGV.delete(arg)
- load File.expand_path(arg.split(/=/, 2)[1])
- $".push 'rbconfig.rb'
- else
- require 'rbconfig'
- end
- ::Config::CONFIG
- end
-
- def initialize(ardir_root, config)
- @ardir = File.expand_path(ardir_root)
- @config = config
- # cache
- @valid_task_re = nil
- end
-
- def config(key)
- @config[key]
- end
-
- def inspect
- "#<#{self.class} #{__id__()}>"
- end
-
- def invoke
- run_metaconfigs
- case task = parsearg_global()
- when nil, 'all'
- parsearg_config
- init_installers
- exec_config
- exec_setup
- exec_install
- else
- case task
- when 'config', 'test'
- ;
- when 'clean', 'distclean'
- @config.load_savefile if File.exist?(@config.savefile)
- else
- @config.load_savefile
- end
- __send__ "parsearg_#{task}"
- init_installers
- __send__ "exec_#{task}"
- end
- end
-
- def run_metaconfigs
- @config.load_script "#{@ardir}/metaconfig"
- end
-
- def init_installers
- @installer = Installer.new(@config, @ardir, File.expand_path('.'))
- end
-
- #
- # Hook Script API bases
- #
-
- def srcdir_root
- @ardir
- end
-
- def objdir_root
- '.'
- end
-
- def relpath
- '.'
- end
-
- #
- # Option Parsing
- #
-
- def parsearg_global
- while arg = ARGV.shift
- case arg
- when /\A\w+\z/
- setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
- return arg
- when '-q', '--quiet'
- @config.verbose = false
- when '--verbose'
- @config.verbose = true
- when '--help'
- print_usage $stdout
- exit 0
- when '--version'
- puts "#{File.basename($0)} version #{Version}"
- exit 0
- when '--copyright'
- puts Copyright
- exit 0
- else
- setup_rb_error "unknown global option '#{arg}'"
- end
- end
- nil
- end
-
- def valid_task?(t)
- valid_task_re() =~ t
- end
-
- def valid_task_re
- @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
- end
-
- def parsearg_no_options
- unless ARGV.empty?
- task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
- setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
- end
- end
-
- alias parsearg_show parsearg_no_options
- alias parsearg_setup parsearg_no_options
- alias parsearg_test parsearg_no_options
- alias parsearg_clean parsearg_no_options
- alias parsearg_distclean parsearg_no_options
-
- def parsearg_config
- evalopt = []
- set = []
- @config.config_opt = []
- while i = ARGV.shift
- if /\A--?\z/ =~ i
- @config.config_opt = ARGV.dup
- break
- end
- name, value = *@config.parse_opt(i)
- if @config.value_config?(name)
- @config[name] = value
- else
- evalopt.push [name, value]
- end
- set.push name
- end
- evalopt.each do |name, value|
- @config.lookup(name).evaluate value, @config
- end
- # Check if configuration is valid
- set.each do |n|
- @config[n] if @config.value_config?(n)
- end
- end
-
- def parsearg_install
- @config.no_harm = false
- @config.install_prefix = ''
- while a = ARGV.shift
- case a
- when '--no-harm'
- @config.no_harm = true
- when /\A--prefix=/
- path = a.split(/=/, 2)[1]
- path = File.expand_path(path) unless path[0,1] == '/'
- @config.install_prefix = path
- else
- setup_rb_error "install: unknown option #{a}"
- end
- end
- end
-
- def print_usage(out)
- out.puts 'Typical Installation Procedure:'
- out.puts " $ ruby #{File.basename $0} config"
- out.puts " $ ruby #{File.basename $0} setup"
- out.puts " # ruby #{File.basename $0} install (may require root privilege)"
- out.puts
- out.puts 'Detailed Usage:'
- out.puts " ruby #{File.basename $0}