mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
brew man
This commit is contained in:
parent
891030227e
commit
e62a0c65ef
@ -1,101 +0,0 @@
|
||||
require "coveralls/version"
|
||||
require "coveralls/configuration"
|
||||
require "coveralls/api"
|
||||
require "coveralls/output"
|
||||
require "coveralls/simplecov"
|
||||
|
||||
module Coveralls
|
||||
extend self
|
||||
|
||||
class NilFormatter
|
||||
def format(result)
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :testing, :noisy, :run_locally
|
||||
|
||||
def wear!(simplecov_setting=nil, &block)
|
||||
setup!
|
||||
start! simplecov_setting, &block
|
||||
end
|
||||
|
||||
def wear_merged!(simplecov_setting=nil, &block)
|
||||
require 'simplecov'
|
||||
@@adapter = :simplecov
|
||||
::SimpleCov.formatter = NilFormatter
|
||||
start! simplecov_setting, &block
|
||||
end
|
||||
|
||||
def push!
|
||||
require 'simplecov'
|
||||
result = ::SimpleCov::ResultMerger.merged_result
|
||||
Coveralls::SimpleCov::Formatter.new.format result
|
||||
end
|
||||
|
||||
def setup!
|
||||
# Try to load up SimpleCov.
|
||||
@@adapter = nil
|
||||
if defined?(::SimpleCov)
|
||||
@@adapter = :simplecov
|
||||
else
|
||||
begin
|
||||
require 'simplecov'
|
||||
@@adapter = :simplecov if defined?(::SimpleCov)
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
# Load the appropriate adapter.
|
||||
if @@adapter == :simplecov
|
||||
::SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
||||
Coveralls::Output.puts("[Coveralls] Set up the SimpleCov formatter.", :color => "green")
|
||||
else
|
||||
Coveralls::Output.puts("[Coveralls] Couldn't find an appropriate adapter.", :color => "red")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def start!(simplecov_setting = 'test_frameworks', &block)
|
||||
if @@adapter == :simplecov
|
||||
::SimpleCov.add_filter 'vendor'
|
||||
|
||||
if simplecov_setting
|
||||
Coveralls::Output.puts("[Coveralls] Using SimpleCov's '#{simplecov_setting}' settings.", :color => "green")
|
||||
if block_given?
|
||||
::SimpleCov.start(simplecov_setting) { instance_eval(&block)}
|
||||
else
|
||||
::SimpleCov.start(simplecov_setting)
|
||||
end
|
||||
elsif block
|
||||
Coveralls::Output.puts("[Coveralls] Using SimpleCov settings defined in block.", :color => "green")
|
||||
::SimpleCov.start { instance_eval(&block) }
|
||||
else
|
||||
Coveralls::Output.puts("[Coveralls] Using SimpleCov's default settings.", :color => "green")
|
||||
::SimpleCov.start
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def should_run?
|
||||
# Fail early if we're not on a CI
|
||||
unless will_run?
|
||||
Coveralls::Output.puts("[Coveralls] Outside the CI environment, not sending data.", :color => "yellow")
|
||||
return false
|
||||
end
|
||||
|
||||
if ENV["COVERALLS_RUN_LOCALLY"] || (defined?(@run_locally) && @run_locally)
|
||||
Coveralls::Output.puts("[Coveralls] Creating a new job on Coveralls from local coverage results.", :color => "cyan")
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def will_run?
|
||||
ENV["CI"] || ENV["JENKINS_URL"] || ENV['TDDIUM'] ||
|
||||
ENV["COVERALLS_RUN_LOCALLY"] || (defined?(@testing) && @testing)
|
||||
end
|
||||
|
||||
def noisy?
|
||||
ENV["COVERALLS_NOISY"] || (defined?(@noisy) && @noisy)
|
||||
end
|
||||
end
|
@ -1,128 +0,0 @@
|
||||
require 'json'
|
||||
require 'net/https'
|
||||
require 'tempfile'
|
||||
|
||||
module Coveralls
|
||||
class API
|
||||
if ENV['COVERALLS_ENDPOINT']
|
||||
API_HOST = ENV['COVERALLS_ENDPOINT']
|
||||
API_DOMAIN = ENV['COVERALLS_ENDPOINT']
|
||||
else
|
||||
API_HOST = ENV['COVERALLS_DEVELOPMENT'] ? "localhost:3000" : "coveralls.io"
|
||||
API_PROTOCOL = ENV['COVERALLS_DEVELOPMENT'] ? "http" : "https"
|
||||
API_DOMAIN = "#{API_PROTOCOL}://#{API_HOST}"
|
||||
end
|
||||
|
||||
API_BASE = "#{API_DOMAIN}/api/v1"
|
||||
|
||||
def self.post_json(endpoint, hash)
|
||||
disable_net_blockers!
|
||||
|
||||
uri = endpoint_to_uri(endpoint)
|
||||
|
||||
Coveralls::Output.puts("#{ JSON.pretty_generate(hash) }", :color => "green") if ENV['COVERALLS_DEBUG']
|
||||
Coveralls::Output.puts("[Coveralls] Submitting to #{API_BASE}", :color => "cyan")
|
||||
|
||||
client = build_client(uri)
|
||||
request = build_request(uri.path, hash)
|
||||
|
||||
response = client.request(request)
|
||||
|
||||
response_hash = JSON.load(response.body.to_str)
|
||||
|
||||
if response_hash['message']
|
||||
Coveralls::Output.puts("[Coveralls] #{ response_hash['message'] }", :color => "cyan")
|
||||
end
|
||||
|
||||
if response_hash['url']
|
||||
Coveralls::Output.puts("[Coveralls] #{ Coveralls::Output.format(response_hash['url'], :color => "underline") }", :color => "cyan")
|
||||
end
|
||||
|
||||
case response
|
||||
when Net::HTTPServiceUnavailable
|
||||
Coveralls::Output.puts("[Coveralls] API timeout occured, but data should still be processed", :color => "red")
|
||||
when Net::HTTPInternalServerError
|
||||
Coveralls::Output.puts("[Coveralls] API internal error occured, we're on it!", :color => "red")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.disable_net_blockers!
|
||||
begin
|
||||
require 'webmock'
|
||||
|
||||
allow = WebMock::Config.instance.allow || []
|
||||
WebMock::Config.instance.allow = [*allow].push API_HOST
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
begin
|
||||
require 'vcr'
|
||||
|
||||
VCR.send(VCR.version.major < 2 ? :config : :configure) do |c|
|
||||
c.ignore_hosts API_HOST
|
||||
end
|
||||
rescue LoadError
|
||||
end
|
||||
end
|
||||
|
||||
def self.endpoint_to_uri(endpoint)
|
||||
URI.parse("#{API_BASE}/#{endpoint}")
|
||||
end
|
||||
|
||||
def self.build_client(uri)
|
||||
client = Net::HTTP.new(uri.host, uri.port)
|
||||
client.use_ssl = true if uri.port == 443
|
||||
client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
|
||||
unless client.respond_to?(:ssl_version=)
|
||||
Net::HTTP.ssl_context_accessor("ssl_version")
|
||||
end
|
||||
|
||||
client.ssl_version = 'TLSv1'
|
||||
|
||||
client
|
||||
end
|
||||
|
||||
def self.build_request(path, hash)
|
||||
request = Net::HTTP::Post.new(path)
|
||||
boundary = rand(1_000_000).to_s
|
||||
|
||||
request.body = build_request_body(hash, boundary)
|
||||
request.content_type = "multipart/form-data, boundary=#{boundary}"
|
||||
|
||||
request
|
||||
end
|
||||
|
||||
def self.build_request_body(hash, boundary)
|
||||
hash = apified_hash(hash)
|
||||
file = hash_to_file(hash)
|
||||
|
||||
"--#{boundary}\r\n" \
|
||||
"Content-Disposition: form-data; name=\"json_file\"; filename=\"#{File.basename(file.path)}\"\r\n" \
|
||||
"Content-Type: text/plain\r\n\r\n" +
|
||||
File.read(file.path) +
|
||||
"\r\n--#{boundary}--\r\n"
|
||||
end
|
||||
|
||||
def self.hash_to_file(hash)
|
||||
file = nil
|
||||
Tempfile.open(['coveralls-upload', 'json']) do |f|
|
||||
f.write(JSON.dump hash)
|
||||
file = f
|
||||
end
|
||||
File.new(file.path, 'rb')
|
||||
end
|
||||
|
||||
def self.apified_hash hash
|
||||
config = Coveralls::Configuration.configuration
|
||||
if ENV['COVERALLS_DEBUG'] || Coveralls.testing
|
||||
Coveralls::Output.puts "[Coveralls] Submitting with config:", :color => "yellow"
|
||||
output = JSON.pretty_generate(config).gsub(/"repo_token": ?"(.*?)"/,'"repo_token": "[secure]"')
|
||||
Coveralls::Output.puts output, :color => "yellow"
|
||||
end
|
||||
hash.merge(config)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,69 +0,0 @@
|
||||
require "thor"
|
||||
|
||||
module Coveralls
|
||||
class CommandLine < Thor
|
||||
|
||||
desc "push", "Runs your test suite and pushes the coverage results to Coveralls."
|
||||
def push
|
||||
return unless ensure_can_run_locally!
|
||||
ENV["COVERALLS_RUN_LOCALLY"] = "true"
|
||||
cmds = "bundle exec rake"
|
||||
if File.exist?('.travis.yml')
|
||||
cmds = YAML.load_file('.travis.yml')["script"] || cmds rescue cmds
|
||||
end
|
||||
cmds.each { |cmd| system cmd }
|
||||
ENV["COVERALLS_RUN_LOCALLY"] = nil
|
||||
end
|
||||
|
||||
desc "report", "Runs your test suite locally and displays coverage statistics."
|
||||
def report
|
||||
ENV["COVERALLS_NOISY"] = "true"
|
||||
exec "bundle exec rake"
|
||||
ENV["COVERALLS_NOISY"] = nil
|
||||
end
|
||||
|
||||
desc "open", "View this repository on Coveralls."
|
||||
def open
|
||||
open_token_based_url "https://coveralls.io/repos/%@"
|
||||
end
|
||||
|
||||
desc "service", "View this repository on your CI service's website."
|
||||
def service
|
||||
open_token_based_url "https://coveralls.io/repos/%@/service"
|
||||
end
|
||||
|
||||
desc "last", "View the last build for this repository on Coveralls."
|
||||
def last
|
||||
open_token_based_url "https://coveralls.io/repos/%@/last_build"
|
||||
end
|
||||
|
||||
desc "version", "See version"
|
||||
def version
|
||||
Coveralls::Output.puts Coveralls::VERSION
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def open_token_based_url url
|
||||
config = Coveralls::Configuration.configuration
|
||||
if config[:repo_token]
|
||||
url = url.gsub("%@", config[:repo_token])
|
||||
`open #{url}`
|
||||
else
|
||||
Coveralls::Output.puts "No repo_token configured."
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_can_run_locally!
|
||||
config = Coveralls::Configuration.configuration
|
||||
if config[:repo_token].nil?
|
||||
Coveralls::Output.puts "Coveralls cannot run locally because no repo_secret_token is set in .coveralls.yml", :color => "red"
|
||||
Coveralls::Output.puts "Please try again when you get your act together.", :color => "red"
|
||||
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,233 +0,0 @@
|
||||
require 'yaml'
|
||||
require 'securerandom'
|
||||
|
||||
module Coveralls
|
||||
module Configuration
|
||||
|
||||
def self.configuration
|
||||
config = {
|
||||
:environment => self.relevant_env,
|
||||
:git => git
|
||||
}
|
||||
yml = self.yaml_config
|
||||
if yml
|
||||
config[:configuration] = yml
|
||||
config[:repo_token] = yml['repo_token'] || yml['repo_secret_token']
|
||||
end
|
||||
if ENV['COVERALLS_REPO_TOKEN']
|
||||
config[:repo_token] = ENV['COVERALLS_REPO_TOKEN']
|
||||
end
|
||||
if ENV['COVERALLS_PARALLEL'] && ENV['COVERALLS_PARALLEL'] != "false"
|
||||
config[:parallel] = true
|
||||
end
|
||||
if ENV['COVERALLS_FLAG_NAME']
|
||||
config[:flag_name] = ENV['COVERALLS_FLAG_NAME']
|
||||
end
|
||||
if ENV['TRAVIS']
|
||||
set_service_params_for_travis(config, yml ? yml['service_name'] : nil)
|
||||
elsif ENV['CIRCLECI']
|
||||
set_service_params_for_circleci(config)
|
||||
elsif ENV['SEMAPHORE']
|
||||
set_service_params_for_semaphore(config)
|
||||
elsif ENV['JENKINS_URL'] || ENV['JENKINS_HOME']
|
||||
set_service_params_for_jenkins(config)
|
||||
elsif ENV['APPVEYOR']
|
||||
set_service_params_for_appveyor(config)
|
||||
elsif ENV['TDDIUM']
|
||||
set_service_params_for_tddium(config)
|
||||
elsif ENV['GITLAB_CI']
|
||||
set_service_params_for_gitlab(config)
|
||||
elsif ENV['COVERALLS_RUN_LOCALLY'] || Coveralls.testing
|
||||
set_service_params_for_coveralls_local(config)
|
||||
end
|
||||
|
||||
# standardized env vars
|
||||
set_standard_service_params_for_generic_ci(config)
|
||||
|
||||
if service_name = ENV['COVERALLS_SERVICE_NAME']
|
||||
config[:service_name] = service_name
|
||||
end
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
def self.set_service_params_for_travis(config, service_name)
|
||||
config[:service_job_id] = ENV['TRAVIS_JOB_ID']
|
||||
config[:service_pull_request] = ENV['TRAVIS_PULL_REQUEST'] unless ENV['TRAVIS_PULL_REQUEST'] == 'false'
|
||||
config[:service_name] = service_name || 'travis-ci'
|
||||
config[:service_branch] = ENV['TRAVIS_BRANCH']
|
||||
end
|
||||
|
||||
def self.set_service_params_for_circleci(config)
|
||||
config[:service_name] = 'circleci'
|
||||
config[:service_number] = ENV['CIRCLE_BUILD_NUM']
|
||||
config[:service_pull_request] = (ENV['CI_PULL_REQUEST'] || "")[/(\d+)$/,1]
|
||||
config[:parallel] = ENV['CIRCLE_NODE_TOTAL'].to_i > 1
|
||||
config[:service_job_number] = ENV['CIRCLE_NODE_INDEX']
|
||||
end
|
||||
|
||||
def self.set_service_params_for_semaphore(config)
|
||||
config[:service_name] = 'semaphore'
|
||||
config[:service_number] = ENV['SEMAPHORE_BUILD_NUMBER']
|
||||
config[:service_pull_request] = ENV['PULL_REQUEST_NUMBER']
|
||||
end
|
||||
|
||||
def self.set_service_params_for_jenkins(config)
|
||||
config[:service_name] = 'jenkins'
|
||||
config[:service_number] = ENV['BUILD_NUMBER']
|
||||
config[:service_branch] = ENV['BRANCH_NAME']
|
||||
config[:service_pull_request] = ENV['ghprbPullId']
|
||||
end
|
||||
|
||||
def self.set_service_params_for_appveyor(config)
|
||||
config[:service_name] = 'appveyor'
|
||||
config[:service_number] = ENV['APPVEYOR_BUILD_VERSION']
|
||||
config[:service_branch] = ENV['APPVEYOR_REPO_BRANCH']
|
||||
config[:commit_sha] = ENV['APPVEYOR_REPO_COMMIT']
|
||||
repo_name = ENV['APPVEYOR_REPO_NAME']
|
||||
config[:service_build_url] = 'https://ci.appveyor.com/project/%s/build/%s' % [repo_name, config[:service_number]]
|
||||
end
|
||||
|
||||
def self.set_service_params_for_tddium(config)
|
||||
config[:service_name] = 'tddium'
|
||||
config[:service_number] = ENV['TDDIUM_SESSION_ID']
|
||||
config[:service_job_number] = ENV['TDDIUM_TID']
|
||||
config[:service_pull_request] = ENV['TDDIUM_PR_ID']
|
||||
config[:service_branch] = ENV['TDDIUM_CURRENT_BRANCH']
|
||||
config[:service_build_url] = "https://ci.solanolabs.com/reports/#{ENV['TDDIUM_SESSION_ID']}"
|
||||
end
|
||||
|
||||
def self.set_service_params_for_gitlab(config)
|
||||
config[:service_name] = 'gitlab-ci'
|
||||
config[:service_job_number] = ENV['CI_BUILD_NAME']
|
||||
config[:service_job_id] = ENV['CI_BUILD_ID']
|
||||
config[:service_branch] = ENV['CI_BUILD_REF_NAME']
|
||||
config[:commit_sha] = ENV['CI_BUILD_REF']
|
||||
end
|
||||
|
||||
def self.set_service_params_for_coveralls_local(config)
|
||||
config[:service_job_id] = nil
|
||||
config[:service_name] = 'coveralls-ruby'
|
||||
config[:service_event_type] = 'manual'
|
||||
end
|
||||
|
||||
def self.set_standard_service_params_for_generic_ci(config)
|
||||
config[:service_name] ||= ENV['CI_NAME']
|
||||
config[:service_number] ||= ENV['CI_BUILD_NUMBER']
|
||||
config[:service_job_id] ||= ENV['CI_JOB_ID']
|
||||
config[:service_build_url] ||= ENV['CI_BUILD_URL']
|
||||
config[:service_branch] ||= ENV['CI_BRANCH']
|
||||
config[:service_pull_request] ||= (ENV['CI_PULL_REQUEST'] || "")[/(\d+)$/,1]
|
||||
end
|
||||
|
||||
def self.yaml_config
|
||||
if self.configuration_path && File.exist?(self.configuration_path)
|
||||
YAML::load_file(self.configuration_path)
|
||||
end
|
||||
end
|
||||
|
||||
def self.configuration_path
|
||||
File.expand_path(File.join(self.root, ".coveralls.yml")) if self.root
|
||||
end
|
||||
|
||||
def self.root
|
||||
pwd
|
||||
end
|
||||
|
||||
def self.pwd
|
||||
Dir.pwd
|
||||
end
|
||||
|
||||
def self.simplecov_root
|
||||
if defined?(::SimpleCov)
|
||||
::SimpleCov.root
|
||||
end
|
||||
end
|
||||
|
||||
def self.rails_root
|
||||
Rails.root.to_s
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def self.git
|
||||
hash = {}
|
||||
|
||||
Dir.chdir(root) do
|
||||
|
||||
hash[:head] = {
|
||||
:id => ENV.fetch("GIT_ID", `git log -1 --pretty=format:'%H'`),
|
||||
:author_name => ENV.fetch("GIT_AUTHOR_NAME", `git log -1 --pretty=format:'%aN'`),
|
||||
:author_email => ENV.fetch("GIT_AUTHOR_EMAIL", `git log -1 --pretty=format:'%ae'`),
|
||||
:committer_name => ENV.fetch("GIT_COMMITTER_NAME", `git log -1 --pretty=format:'%cN'`),
|
||||
:committer_email => ENV.fetch("GIT_COMMITTER_EMAIL", `git log -1 --pretty=format:'%ce'`),
|
||||
:message => ENV.fetch("GIT_MESSAGE", `git log -1 --pretty=format:'%s'`)
|
||||
}
|
||||
|
||||
# Branch
|
||||
hash[:branch] = ENV.fetch("GIT_BRANCH", `git rev-parse --abbrev-ref HEAD`)
|
||||
|
||||
# Remotes
|
||||
remotes = nil
|
||||
begin
|
||||
remotes = `git remote -v`.split(/\n/).map do |remote|
|
||||
splits = remote.split(" ").compact
|
||||
{:name => splits[0], :url => splits[1]}
|
||||
end.uniq
|
||||
rescue
|
||||
end
|
||||
hash[:remotes] = remotes
|
||||
|
||||
end
|
||||
|
||||
hash
|
||||
|
||||
rescue Exception => e
|
||||
Coveralls::Output.puts "Coveralls git error:", :color => "red"
|
||||
Coveralls::Output.puts e.to_s, :color => "red"
|
||||
nil
|
||||
end
|
||||
|
||||
def self.relevant_env
|
||||
hash = {
|
||||
:pwd => self.pwd,
|
||||
:rails_root => self.rails_root,
|
||||
:simplecov_root => simplecov_root,
|
||||
:gem_version => VERSION
|
||||
}
|
||||
|
||||
hash.merge! begin
|
||||
if ENV['TRAVIS']
|
||||
{
|
||||
:travis_job_id => ENV['TRAVIS_JOB_ID'],
|
||||
:travis_pull_request => ENV['TRAVIS_PULL_REQUEST'],
|
||||
:branch => ENV['TRAVIS_BRANCH']
|
||||
}
|
||||
elsif ENV['CIRCLECI']
|
||||
{
|
||||
:circleci_build_num => ENV['CIRCLE_BUILD_NUM'],
|
||||
:branch => ENV['CIRCLE_BRANCH'],
|
||||
:commit_sha => ENV['CIRCLE_SHA1']
|
||||
}
|
||||
elsif ENV['JENKINS_URL']
|
||||
{
|
||||
:jenkins_build_num => ENV['BUILD_NUMBER'],
|
||||
:jenkins_build_url => ENV['BUILD_URL'],
|
||||
:branch => ENV['GIT_BRANCH'],
|
||||
:commit_sha => ENV['GIT_COMMIT']
|
||||
}
|
||||
elsif ENV['SEMAPHORE']
|
||||
{
|
||||
:branch => ENV['BRANCH_NAME'],
|
||||
:commit_sha => ENV['REVISION']
|
||||
}
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,114 +0,0 @@
|
||||
module Coveralls
|
||||
#
|
||||
# Public: Methods for formatting strings with Term::ANSIColor.
|
||||
# Does not utilize monkey-patching and should play nicely when
|
||||
# included with other libraries.
|
||||
#
|
||||
# All methods are module methods and should be called on
|
||||
# the Coveralls::Output module.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# Coveralls::Output.format("Hello World", :color => "cyan")
|
||||
# # => "\e[36mHello World\e[0m"
|
||||
#
|
||||
# Coveralls::Output.print("Hello World")
|
||||
# # Hello World => nil
|
||||
#
|
||||
# Coveralls::Output.puts("Hello World", :color => "underline")
|
||||
# # Hello World
|
||||
# # => nil
|
||||
#
|
||||
# To silence output completely:
|
||||
#
|
||||
# Coveralls::Output.silent = true
|
||||
#
|
||||
# or set this environment variable:
|
||||
#
|
||||
# COVERALLS_SILENT
|
||||
#
|
||||
# To disable color completely:
|
||||
#
|
||||
# Coveralls::Output.no_color = true
|
||||
|
||||
module Output
|
||||
attr_accessor :silent, :no_color
|
||||
attr_writer :output
|
||||
extend self
|
||||
|
||||
def output
|
||||
(defined?(@output) && @output) || $stdout
|
||||
end
|
||||
|
||||
def no_color?
|
||||
(defined?(@no_color)) && @no_color
|
||||
end
|
||||
|
||||
# Public: Formats the given string with the specified color
|
||||
# through Term::ANSIColor
|
||||
#
|
||||
# string - the text to be formatted
|
||||
# options - The hash of options used for formatting the text:
|
||||
# :color - The color to be passed as a method to
|
||||
# Term::ANSIColor
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# Coveralls::Output.format("Hello World!", :color => "cyan")
|
||||
# # => "\e[36mHello World\e[0m"
|
||||
#
|
||||
# Returns the formatted string.
|
||||
def format(string, options = {})
|
||||
unless no_color?
|
||||
require 'term/ansicolor'
|
||||
if options[:color]
|
||||
options[:color].split(/\s/).reverse_each do |color|
|
||||
if Term::ANSIColor.respond_to?(color.to_sym)
|
||||
string = Term::ANSIColor.send(color.to_sym, string)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
string
|
||||
end
|
||||
|
||||
# Public: Passes .format to Kernel#puts
|
||||
#
|
||||
# string - the text to be formatted
|
||||
# options - The hash of options used for formatting the text:
|
||||
# :color - The color to be passed as a method to
|
||||
# Term::ANSIColor
|
||||
#
|
||||
#
|
||||
# Example
|
||||
#
|
||||
# Coveralls::Output.puts("Hello World", :color => "cyan")
|
||||
#
|
||||
# Returns nil.
|
||||
def puts(string, options = {})
|
||||
return if silent?
|
||||
(options[:output] || output).puts self.format(string, options)
|
||||
end
|
||||
|
||||
# Public: Passes .format to Kernel#print
|
||||
#
|
||||
# string - the text to be formatted
|
||||
# options - The hash of options used for formatting the text:
|
||||
# :color - The color to be passed as a method to
|
||||
# Term::ANSIColor
|
||||
#
|
||||
# Example
|
||||
#
|
||||
# Coveralls::Output.print("Hello World!", :color => "underline")
|
||||
#
|
||||
# Returns nil.
|
||||
def print(string, options = {})
|
||||
return if silent?
|
||||
(options[:output] || output).print self.format(string, options)
|
||||
end
|
||||
|
||||
def silent?
|
||||
ENV["COVERALLS_SILENT"] || (defined?(@silent) && @silent)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,19 +0,0 @@
|
||||
require 'rake'
|
||||
require 'rake/tasklib'
|
||||
|
||||
module Coveralls
|
||||
class RakeTask < ::Rake::TaskLib
|
||||
include ::Rake::DSL if defined?(::Rake::DSL)
|
||||
|
||||
def initialize(*args, &task_block)
|
||||
namespace :coveralls do
|
||||
desc "Push latest coverage results to Coveralls.io"
|
||||
task :push do
|
||||
require 'coveralls'
|
||||
Coveralls.push!
|
||||
end
|
||||
end
|
||||
end # initialize
|
||||
|
||||
end # class
|
||||
end # module
|
@ -1,101 +0,0 @@
|
||||
module Coveralls
|
||||
module SimpleCov
|
||||
class Formatter
|
||||
|
||||
def display_result(result)
|
||||
# Log which files would be submitted.
|
||||
if result.files.length > 0
|
||||
Coveralls::Output.puts "[Coveralls] Some handy coverage stats:"
|
||||
else
|
||||
Coveralls::Output.puts "[Coveralls] There are no covered files.", :color => "yellow"
|
||||
end
|
||||
result.files.each do |f|
|
||||
Coveralls::Output.print " * "
|
||||
Coveralls::Output.print short_filename(f.filename).to_s, :color => "cyan"
|
||||
Coveralls::Output.print " => ", :color => "white"
|
||||
cov = "#{f.covered_percent.round}%"
|
||||
if f.covered_percent > 90
|
||||
Coveralls::Output.print cov, :color => "green"
|
||||
elsif f.covered_percent > 80
|
||||
Coveralls::Output.print cov, :color => "yellow"
|
||||
else
|
||||
Coveralls::Output.print cov, :color => "red"
|
||||
end
|
||||
Coveralls::Output.puts ""
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def get_source_files(result)
|
||||
# Gather the source files.
|
||||
source_files = []
|
||||
result.files.each do |file|
|
||||
properties = {}
|
||||
|
||||
# Get Source
|
||||
properties[:source] = File.open(file.filename, "rb:utf-8").read
|
||||
|
||||
# Get the root-relative filename
|
||||
properties[:name] = short_filename(file.filename)
|
||||
|
||||
# Get the coverage
|
||||
properties[:coverage] = file.coverage.dup
|
||||
|
||||
# Skip nocov lines
|
||||
file.lines.each_with_index do |line, i|
|
||||
properties[:coverage][i] = nil if line.skipped?
|
||||
end
|
||||
|
||||
source_files << properties
|
||||
end
|
||||
source_files
|
||||
end
|
||||
|
||||
def format(result)
|
||||
|
||||
unless Coveralls.should_run?
|
||||
if Coveralls.noisy?
|
||||
display_result result
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# Post to Coveralls.
|
||||
API.post_json "jobs",
|
||||
:source_files => get_source_files(result),
|
||||
:test_framework => result.command_name.downcase,
|
||||
:run_at => result.created_at
|
||||
|
||||
Coveralls::Output.puts output_message result
|
||||
|
||||
true
|
||||
|
||||
rescue Exception => e
|
||||
display_error e
|
||||
end
|
||||
|
||||
def display_error(e)
|
||||
Coveralls::Output.puts "Coveralls encountered an exception:", :color => "red"
|
||||
Coveralls::Output.puts e.class.to_s, :color => "red"
|
||||
Coveralls::Output.puts e.message, :color => "red"
|
||||
e.backtrace.each do |line|
|
||||
Coveralls::Output.puts line, :color => "red"
|
||||
end if e.backtrace
|
||||
if e.respond_to?(:response) && e.response
|
||||
Coveralls::Output.puts e.response.to_s, :color => "red"
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def output_message(result)
|
||||
"Coverage is at #{result.covered_percent.round(2) rescue result.covered_percent.round}%.\nCoverage report sent to Coveralls."
|
||||
end
|
||||
|
||||
def short_filename(filename)
|
||||
filename = filename.gsub(::SimpleCov.root, '.').gsub(/^\.\//, '') if ::SimpleCov.root
|
||||
filename
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,3 +0,0 @@
|
||||
module Coveralls
|
||||
VERSION = "0.8.23"
|
||||
end
|
@ -1,127 +0,0 @@
|
||||
require 'tins/xt/full'
|
||||
|
||||
module Term
|
||||
|
||||
# The ANSIColor module can be used for namespacing and mixed into your own
|
||||
# classes.
|
||||
module ANSIColor
|
||||
require 'term/ansicolor/version'
|
||||
require 'term/ansicolor/attribute'
|
||||
require 'term/ansicolor/rgb_triple'
|
||||
require 'term/ansicolor/hsl_triple'
|
||||
require 'term/ansicolor/ppm_reader'
|
||||
require 'term/ansicolor/attribute/text'
|
||||
require 'term/ansicolor/attribute/color8'
|
||||
require 'term/ansicolor/attribute/intense_color8'
|
||||
require 'term/ansicolor/attribute/color256'
|
||||
require 'term/ansicolor/movement'
|
||||
|
||||
include Term::ANSIColor::Movement
|
||||
|
||||
# :stopdoc:
|
||||
ATTRIBUTE_NAMES = Attribute.named_attributes.map(&:name)
|
||||
# :startdoc:
|
||||
|
||||
# Returns true if Term::ANSIColor supports the +feature+.
|
||||
#
|
||||
# The feature :clear, that is mixing the clear color attribute into String,
|
||||
# is only supported on ruby implementations, that do *not* already
|
||||
# implement the String#clear method. It's better to use the reset color
|
||||
# attribute instead.
|
||||
def support?(feature)
|
||||
case feature
|
||||
when :clear
|
||||
!String.instance_methods(false).map(&:to_sym).include?(:clear)
|
||||
end
|
||||
end
|
||||
# Returns true, if the coloring function of this module
|
||||
# is switched on, false otherwise.
|
||||
def self.coloring?
|
||||
@coloring
|
||||
end
|
||||
|
||||
# Turns the coloring on or off globally, so you can easily do
|
||||
# this for example:
|
||||
# Term::ANSIColor::coloring = STDOUT.isatty
|
||||
def self.coloring=(val)
|
||||
@coloring = val
|
||||
end
|
||||
self.coloring = true
|
||||
|
||||
def self.create_color_method(color_name, color_value)
|
||||
module_eval <<-EOT
|
||||
def #{color_name}(string = nil, &block)
|
||||
color(:#{color_name}, string, &block)
|
||||
end
|
||||
EOT
|
||||
self
|
||||
end
|
||||
|
||||
for attribute in Attribute.named_attributes
|
||||
create_color_method(attribute.name, attribute.code)
|
||||
end
|
||||
|
||||
# Regular expression that is used to scan for ANSI-Attributes while
|
||||
# uncoloring strings.
|
||||
COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9]|[34]8;5;\d{1,3})?m/
|
||||
|
||||
# Returns an uncolored version of the string, that is all
|
||||
# ANSI-Attributes are stripped from the string.
|
||||
def uncolor(string = nil) # :yields:
|
||||
if block_given?
|
||||
yield.to_str.gsub(COLORED_REGEXP, '')
|
||||
elsif string.respond_to?(:to_str)
|
||||
string.to_str.gsub(COLORED_REGEXP, '')
|
||||
elsif respond_to?(:to_str)
|
||||
to_str.gsub(COLORED_REGEXP, '')
|
||||
else
|
||||
''
|
||||
end.extend(Term::ANSIColor)
|
||||
end
|
||||
|
||||
alias uncolored uncolor
|
||||
|
||||
# Return +string+ or the result string of the given +block+ colored with
|
||||
# color +name+. If string isn't a string only the escape sequence to switch
|
||||
# on the color +name+ is returned.
|
||||
def color(name, string = nil, &block)
|
||||
attribute = Attribute[name] or raise ArgumentError, "unknown attribute #{name.inspect}"
|
||||
result = ''
|
||||
result << "\e[#{attribute.code}m" if Term::ANSIColor.coloring?
|
||||
if block_given?
|
||||
result << yield.to_s
|
||||
elsif string.respond_to?(:to_str)
|
||||
result << string.to_str
|
||||
elsif respond_to?(:to_str)
|
||||
result << to_str
|
||||
else
|
||||
return result #only switch on
|
||||
end
|
||||
result << "\e[0m" if Term::ANSIColor.coloring?
|
||||
result.extend(Term::ANSIColor)
|
||||
end
|
||||
|
||||
def on_color(name, string = nil, &block)
|
||||
attribute = Attribute[name] or raise ArgumentError, "unknown attribute #{name.inspect}"
|
||||
color("on_#{attribute.name}", string, &block)
|
||||
end
|
||||
|
||||
class << self
|
||||
# Returns an array of all Term::ANSIColor attributes as symbols.
|
||||
def term_ansicolor_attributes
|
||||
::Term::ANSIColor::ATTRIBUTE_NAMES
|
||||
end
|
||||
|
||||
alias attributes term_ansicolor_attributes
|
||||
end
|
||||
|
||||
# Returns an array of all Term::ANSIColor attributes as symbols.
|
||||
def term_ansicolor_attributes
|
||||
::Term::ANSIColor.term_ansicolor_attributes
|
||||
end
|
||||
|
||||
alias attributes term_ansicolor_attributes
|
||||
|
||||
extend self
|
||||
end
|
||||
end
|
@ -1,142 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class Attribute
|
||||
@__store__ = {}
|
||||
|
||||
if RUBY_VERSION < '1.9'
|
||||
@__order__ = []
|
||||
|
||||
def self.set(name, code, options = {})
|
||||
name = name.to_sym
|
||||
result = @__store__[name] = new(name, code, options)
|
||||
@__order__ << name
|
||||
@rgb_colors = nil
|
||||
result
|
||||
end
|
||||
|
||||
def self.attributes(&block)
|
||||
@__order__.map { |name| @__store__[name] }
|
||||
end
|
||||
else
|
||||
def self.set(name, code, options = {})
|
||||
name = name.to_sym
|
||||
result = @__store__[name] = new(name, code, options)
|
||||
@rgb_colors = nil
|
||||
result
|
||||
end
|
||||
|
||||
def self.attributes(&block)
|
||||
@__store__.each_value(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def self.[](name)
|
||||
case
|
||||
when self === name then name
|
||||
when Array === name then nearest_rgb_color name
|
||||
when name.respond_to?(:to_rgb_triple) then nearest_rgb_color(name.to_rgb_triple.to_a)
|
||||
when name.to_s =~ /\A(on_)?(\d+)\z/ then get "#$1color#$2"
|
||||
when name.to_s =~ /\A#([0-9a-f]{3}){1,2}\z/i then nearest_rgb_color name
|
||||
when name.to_s =~ /\Aon_#([0-9a-f]{3}){1,2}\z/i then nearest_rgb_on_color name
|
||||
else get name
|
||||
end
|
||||
end
|
||||
|
||||
def self.get(name)
|
||||
@__store__[name.to_sym]
|
||||
end
|
||||
|
||||
def self.rgb_colors(options = {}, &block)
|
||||
colors = @rgb_colors ||= attributes.select(&:rgb_color?)
|
||||
if options.key?(:gray) && !options[:gray]
|
||||
colors = colors.reject(&:gray?)
|
||||
end
|
||||
colors.each(&block)
|
||||
end
|
||||
|
||||
def self.named_attributes(&block)
|
||||
@named_attributes ||= attributes.reject(&:rgb_color?).each(&block)
|
||||
end
|
||||
|
||||
def self.nearest_rgb_color(color, options = {})
|
||||
rgb = RGBTriple[color]
|
||||
colors = rgb_colors(options)
|
||||
colors.reject(&:background?).min_by { |c| c.distance_to(rgb, options) }
|
||||
end
|
||||
|
||||
def self.nearest_rgb_on_color(color, options = {})
|
||||
rgb = RGBTriple[color]
|
||||
colors = rgb_colors(options)
|
||||
colors.select(&:background?).min_by { |c| c.distance_to(rgb, options) }
|
||||
end
|
||||
|
||||
def initialize(name, code, options = {})
|
||||
@name = name.to_sym
|
||||
@code = code.to_s
|
||||
if html = options[:html]
|
||||
@rgb = RGBTriple.from_html(html)
|
||||
elsif !options.empty?
|
||||
@rgb = RGBTriple.from_hash(options)
|
||||
else
|
||||
@rgb = nil # prevent instance variable not initialized warnings
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :name
|
||||
|
||||
def code
|
||||
if rgb_color?
|
||||
background? ? "48;5;#{@code}" : "38;5;#{@code}"
|
||||
else
|
||||
@code
|
||||
end
|
||||
end
|
||||
|
||||
def apply(string = nil, &block)
|
||||
::Term::ANSIColor.color(self, string, &block)
|
||||
end
|
||||
|
||||
def background?
|
||||
@name.to_s.start_with?('on_')
|
||||
end
|
||||
|
||||
attr_reader :rgb
|
||||
|
||||
def rgb_color?
|
||||
!!@rgb
|
||||
end
|
||||
|
||||
def gray?
|
||||
rgb_color? && to_rgb_triple.gray?
|
||||
end
|
||||
|
||||
def to_rgb_triple
|
||||
@rgb
|
||||
end
|
||||
|
||||
def distance_to(other, options = {})
|
||||
if our_rgb = to_rgb_triple and
|
||||
other.respond_to?(:to_rgb_triple) and
|
||||
other_rgb = other.to_rgb_triple
|
||||
then
|
||||
our_rgb.distance_to(other_rgb, options)
|
||||
else
|
||||
1 / 0.0
|
||||
end
|
||||
end
|
||||
|
||||
def gradient_to(other, options = {})
|
||||
if our_rgb = to_rgb_triple and
|
||||
other.respond_to?(:to_rgb_triple) and
|
||||
other_rgb = other.to_rgb_triple
|
||||
then
|
||||
our_rgb.gradient_to(other_rgb, options).map do |rgb_triple|
|
||||
self.class.nearest_rgb_color(rgb_triple, options)
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,69 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class Attribute
|
||||
class Color256
|
||||
Attribute.set :color0, 0, :html => '#000000'
|
||||
Attribute.set :color1, 1, :html => '#800000'
|
||||
Attribute.set :color2, 2, :html => '#808000'
|
||||
Attribute.set :color3, 3, :html => '#808000'
|
||||
Attribute.set :color4, 4, :html => '#000080'
|
||||
Attribute.set :color5, 5, :html => '#800080'
|
||||
Attribute.set :color6, 6, :html => '#008080'
|
||||
Attribute.set :color7, 7, :html => '#c0c0c0'
|
||||
|
||||
Attribute.set :color8, 8, :html => '#808080'
|
||||
Attribute.set :color9, 9, :html => '#ff0000'
|
||||
Attribute.set :color10, 10, :html => '#00ff00'
|
||||
Attribute.set :color11, 11, :html => '#ffff00'
|
||||
Attribute.set :color12, 12, :html => '#0000ff'
|
||||
Attribute.set :color13, 13, :html => '#ff00ff'
|
||||
Attribute.set :color14, 14, :html => '#00ffff'
|
||||
Attribute.set :color15, 15, :html => '#ffffff'
|
||||
|
||||
steps = [ 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff ]
|
||||
|
||||
for i in 16..231
|
||||
red, green, blue = (i - 16).to_s(6).rjust(3, '0').each_char.map { |c| steps[c.to_i] }
|
||||
Attribute.set "color#{i}", i, :red => red, :green => green, :blue => blue
|
||||
end
|
||||
|
||||
grey = 8
|
||||
for i in 232..255
|
||||
Attribute.set "color#{i}", i, :red => grey, :green => grey, :blue => grey
|
||||
grey += 10
|
||||
end
|
||||
|
||||
Attribute.set :on_color0, 0, :html => '#000000'
|
||||
Attribute.set :on_color1, 1, :html => '#800000'
|
||||
Attribute.set :on_color2, 2, :html => '#808000'
|
||||
Attribute.set :on_color3, 3, :html => '#808000'
|
||||
Attribute.set :on_color4, 4, :html => '#000080'
|
||||
Attribute.set :on_color5, 5, :html => '#800080'
|
||||
Attribute.set :on_color6, 6, :html => '#008080'
|
||||
Attribute.set :on_color7, 7, :html => '#c0c0c0'
|
||||
|
||||
Attribute.set :on_color8, 8, :html => '#808080'
|
||||
Attribute.set :on_color9, 9, :html => '#ff0000'
|
||||
Attribute.set :on_color10, 10, :html => '#00ff00'
|
||||
Attribute.set :on_color11, 11, :html => '#ffff00'
|
||||
Attribute.set :on_color12, 12, :html => '#0000ff'
|
||||
Attribute.set :on_color13, 13, :html => '#ff00ff'
|
||||
Attribute.set :on_color14, 14, :html => '#00ffff'
|
||||
Attribute.set :on_color15, 15, :html => '#ffffff'
|
||||
|
||||
steps = [ 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff ]
|
||||
|
||||
for i in 16..231
|
||||
red, green, blue = (i - 16).to_s(6).rjust(3, '0').each_char.map { |c| steps[c.to_i] }
|
||||
Attribute.set "on_color#{i}", i, :red => red, :green => green, :blue => blue
|
||||
end
|
||||
|
||||
grey = 8
|
||||
for i in 232..255
|
||||
Attribute.set "on_color#{i}", i, :red => grey, :green => grey, :blue => grey
|
||||
grey += 10
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,25 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class Attribute
|
||||
class Color8
|
||||
Attribute.set :black, 30
|
||||
Attribute.set :red, 31
|
||||
Attribute.set :green, 32
|
||||
Attribute.set :yellow, 33
|
||||
Attribute.set :blue, 34
|
||||
Attribute.set :magenta, 35
|
||||
Attribute.set :cyan, 36
|
||||
Attribute.set :white, 37
|
||||
|
||||
Attribute.set :on_black, 40
|
||||
Attribute.set :on_red, 41
|
||||
Attribute.set :on_green, 42
|
||||
Attribute.set :on_yellow, 43
|
||||
Attribute.set :on_blue, 44
|
||||
Attribute.set :on_magenta, 45
|
||||
Attribute.set :on_cyan, 46
|
||||
Attribute.set :on_white, 47
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,43 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class Attribute
|
||||
class IntenseColor8
|
||||
# High intensity, aixterm (works in OS X)
|
||||
Attribute.set :intense_black, 90
|
||||
Attribute.set :bright_black, 90
|
||||
Attribute.set :intense_red, 91
|
||||
Attribute.set :bright_red, 91
|
||||
Attribute.set :intense_green, 92
|
||||
Attribute.set :bright_green, 92
|
||||
Attribute.set :intense_yellow, 93
|
||||
Attribute.set :bright_yellow, 93
|
||||
Attribute.set :intense_blue, 94
|
||||
Attribute.set :bright_blue, 94
|
||||
Attribute.set :intense_magenta, 95
|
||||
Attribute.set :bright_magenta, 95
|
||||
Attribute.set :intense_cyan, 96
|
||||
Attribute.set :bright_cyan, 96
|
||||
Attribute.set :intense_white, 97
|
||||
Attribute.set :bright_white, 97
|
||||
|
||||
# High intensity background, aixterm (works in OS X)
|
||||
Attribute.set :on_intense_black, 100
|
||||
Attribute.set :on_bright_black, 100
|
||||
Attribute.set :on_intense_red, 101
|
||||
Attribute.set :on_bright_red, 101
|
||||
Attribute.set :on_intense_green, 102
|
||||
Attribute.set :on_bright_green, 102
|
||||
Attribute.set :on_intense_yellow, 103
|
||||
Attribute.set :on_bright_yellow, 103
|
||||
Attribute.set :on_intense_blue, 104
|
||||
Attribute.set :on_bright_blue, 104
|
||||
Attribute.set :on_intense_magenta, 105
|
||||
Attribute.set :on_bright_magenta, 105
|
||||
Attribute.set :on_intense_cyan, 106
|
||||
Attribute.set :on_bright_cyan, 106
|
||||
Attribute.set :on_intense_white, 107
|
||||
Attribute.set :on_bright_white, 107
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,23 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class Attribute
|
||||
class Text
|
||||
Attribute.set :clear, 0 # String#clear already used in String
|
||||
Attribute.set :reset, 0 # synonym for :clear
|
||||
Attribute.set :bold, 1
|
||||
Attribute.set :dark, 2
|
||||
Attribute.set :faint, 2
|
||||
Attribute.set :italic, 3 # not widely implemented
|
||||
Attribute.set :underline, 4
|
||||
Attribute.set :underscore, 4 # synonym for :underline
|
||||
Attribute.set :blink, 5
|
||||
Attribute.set :rapid_blink, 6 # not widely implemented
|
||||
Attribute.set :reverse, 7 # String#reverse already used in String
|
||||
Attribute.set :negative, 7 # synonym for :reverse
|
||||
Attribute.set :concealed, 8
|
||||
Attribute.set :conceal, 8 # synonym for :concealed
|
||||
Attribute.set :strikethrough, 9 # not widely implemented
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,169 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class HSLTriple
|
||||
def self.from_rgb_triple(rgb)
|
||||
ps = rgb.to_a.map { |x| x / 255.0 }
|
||||
p_min = ps.min
|
||||
p_max = ps.max
|
||||
p_red, p_green, p_blue = ps
|
||||
|
||||
diff = p_max - p_min
|
||||
l = (p_max + p_min) / 2
|
||||
|
||||
if diff.zero?
|
||||
h = s = 0.0
|
||||
else
|
||||
if l < 0.5
|
||||
s = diff / (p_max + p_min)
|
||||
else
|
||||
s = diff / (2 - p_max - p_min)
|
||||
end
|
||||
|
||||
diff_r = ( ( ( p_max - p_red ) / 6 ) + ( diff / 2 ) ) / diff
|
||||
diff_g = ( ( ( p_max - p_green ) / 6 ) + ( diff / 2 ) ) / diff
|
||||
diff_b = ( ( ( p_max - p_blue ) / 6 ) + ( diff / 2 ) ) / diff
|
||||
|
||||
h = case p_max
|
||||
when p_red
|
||||
diff_b - diff_g
|
||||
when p_green
|
||||
(1 / 3.0) + diff_r - diff_b
|
||||
when p_blue
|
||||
(2 / 3.0) + diff_g - diff_r
|
||||
end
|
||||
|
||||
h < 0 and h += 1
|
||||
h > 1 and h -= 1
|
||||
end
|
||||
from_hash(
|
||||
hue: 360 * h,
|
||||
saturation: 100 * s,
|
||||
lightness: 100 * l
|
||||
)
|
||||
end
|
||||
|
||||
def self.from_css(css)
|
||||
case css
|
||||
when /\A\s*hsl\(\s*([^,\s]+)\s*,\s*([^%\s]+)\s*%\s*,\s*([^%\s]+)\s*%\s*\)\z/
|
||||
new(Float($1), Float($2), Float($3))
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_hash(options)
|
||||
new(
|
||||
options[:hue].to_f,
|
||||
options[:saturation].to_f,
|
||||
options[:lightness].to_f
|
||||
)
|
||||
end
|
||||
|
||||
def self.[](thing)
|
||||
case
|
||||
when thing.respond_to?(:to_hsl_triple) then thing.to_hsl_triple
|
||||
when thing.respond_to?(:to_hash) then from_hash(thing.to_hash)
|
||||
when thing.respond_to?(:to_str)
|
||||
thing = thing.to_str
|
||||
from_css(thing.to_str) ||
|
||||
Term::ANSIColor::RGBTriple.from_html(thing).full?(:to_hsl_triple) ||
|
||||
Term::ANSIColor::RGBTriple.from_css(thing).full?(:to_hsl_triple)
|
||||
else raise ArgumentError, "cannot convert #{thing.inspect} into #{self}"
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(hue, saturation, lightness)
|
||||
@hue = Float(hue) % 360
|
||||
@saturation = [ [ Float(saturation), 0 ].max, 100 ].min
|
||||
@lightness = [ [ Float(lightness), 0 ].max, 100 ].min
|
||||
end
|
||||
|
||||
attr_reader :hue
|
||||
|
||||
attr_reader :saturation
|
||||
|
||||
attr_reader :lightness
|
||||
|
||||
def lighten(percentage)
|
||||
self.class.new(@hue, @saturation, @lightness + percentage)
|
||||
end
|
||||
|
||||
def darken(percentage)
|
||||
self.class.new(@hue, @saturation, @lightness - percentage)
|
||||
end
|
||||
|
||||
def saturate(percentage)
|
||||
self.class.new(@hue, @saturation + percentage, @lightness)
|
||||
end
|
||||
|
||||
def desaturate(percentage)
|
||||
self.class.new(@hue, @saturation - percentage, @lightness)
|
||||
end
|
||||
|
||||
def adjust_hue(degree)
|
||||
self.class.new(@hue + degree, @saturation, @lightness)
|
||||
end
|
||||
|
||||
def grayscale
|
||||
self.class.new(@hue, 0, @lightness)
|
||||
end
|
||||
|
||||
def complement
|
||||
adjust_hue(180)
|
||||
end
|
||||
|
||||
def hue2rgb(x, y, h)
|
||||
h < 0 and h += 1
|
||||
h > 1 and h -= 1
|
||||
(6 * h) < 1 and return x + (y - x) * 6 * h
|
||||
(2 * h) < 1 and return y
|
||||
(3 * h) < 2 and return x + (y - x) * ( (2 / 3.0) - h ) * 6
|
||||
x
|
||||
end
|
||||
private :hue2rgb
|
||||
|
||||
def to_rgb_triple
|
||||
h = @hue / 360.0
|
||||
s = @saturation / 100.0
|
||||
l = @lightness / 100.0
|
||||
|
||||
if s.zero?
|
||||
r = 255 * l
|
||||
g = 255 * l
|
||||
b = 255 * l
|
||||
else
|
||||
if l < 0.5
|
||||
y = l * (1 + s)
|
||||
else
|
||||
y = (l + s) - (s * l)
|
||||
end
|
||||
|
||||
x = 2 * l - y
|
||||
|
||||
r = 255 * hue2rgb(x, y, h + (1 / 3.0))
|
||||
g = 255 * hue2rgb(x, y, h)
|
||||
b = 255 * hue2rgb(x, y, h - (1 / 3.0))
|
||||
end
|
||||
Term::ANSIColor::RGBTriple.new(r.round, g.round, b.round)
|
||||
end
|
||||
|
||||
def to_hsl_triple
|
||||
self
|
||||
end
|
||||
|
||||
def css
|
||||
"hsl(%s,%s%%,%s%%)" % [ @hue, @saturation, @lightness ]
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
to_rgb_triple == other.to_rgb_triple
|
||||
end
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
if Term::ANSIColor::RGBTriple.method_defined?(name)
|
||||
to_rgb_triple.send(name, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,108 +0,0 @@
|
||||
require 'tins/terminal'
|
||||
|
||||
module Term
|
||||
module ANSIColor
|
||||
module Movement
|
||||
def terminal_lines
|
||||
Tins::Terminal.lines
|
||||
end
|
||||
|
||||
def terminal_columns
|
||||
Tins::Terminal.columns
|
||||
end
|
||||
|
||||
def move_to(line = 1, column = 1, string = nil, &block)
|
||||
move_command("\e[#{line.to_i};#{column.to_i}H", string, &block)
|
||||
end
|
||||
|
||||
def move_to_column(column = 1, string = nil, &block)
|
||||
move_command("\e[#{column.to_i}G", string, &block)
|
||||
end
|
||||
|
||||
def move_to_line(line = 1, string = nil, &block)
|
||||
move_command("\e[#{line.to_i}f", string, &block)
|
||||
end
|
||||
|
||||
def move_up(lines = 1, string = nil, &block)
|
||||
move_command("\e[#{lines.to_i}A", string, &block)
|
||||
end
|
||||
|
||||
def move_down(lines = 1, string = nil, &block)
|
||||
move_command("\e[#{lines.to_i}B", string, &block)
|
||||
end
|
||||
|
||||
def move_forward(columns = 1, string = nil, &block)
|
||||
move_command("\e[#{columns.to_i}C", string, &block)
|
||||
end
|
||||
|
||||
def move_backward(columns = 1, string = nil, &block)
|
||||
move_command("\e[#{columns.to_i}D", string, &block)
|
||||
end
|
||||
|
||||
def move_to_next_line(lines = 1, string = nil, &block)
|
||||
move_command("\e[#{lines}E", string, &block)
|
||||
end
|
||||
|
||||
def move_to_previous_line(lines = 1, string = nil, &block)
|
||||
move_command("\e[#{lines}F", string, &block)
|
||||
end
|
||||
|
||||
def move_home(string = nil, &block)
|
||||
move_to(1, 1, string, &block)
|
||||
end
|
||||
|
||||
def clear_screen(string = nil, &block)
|
||||
erase_in_display(2, string, &block)
|
||||
end
|
||||
|
||||
def erase_in_display(n = 0, string = nil, &block)
|
||||
move_command("\e[#{n}J", string, &block)
|
||||
end
|
||||
|
||||
def erase_in_line(n = 0, string = nil, &block)
|
||||
move_command("\e[#{n}K", string, &block)
|
||||
end
|
||||
|
||||
def scroll_up(pages = 1, string = nil, &block)
|
||||
move_command("\e[#{pages}S", string, &block)
|
||||
end
|
||||
|
||||
def scroll_down(pages = 1, string = nil, &block)
|
||||
move_command("\e[#{pages}T", string, &block)
|
||||
end
|
||||
|
||||
def save_position(string = nil, &block)
|
||||
move_command("\e[s", string, &block)
|
||||
end
|
||||
|
||||
def restore_position(string = nil, &block)
|
||||
move_command("\e[u", string, &block)
|
||||
end
|
||||
|
||||
def return_to_position(string = nil, &block)
|
||||
save_position("") << move_command("", string, &block) << restore_position("")
|
||||
end
|
||||
|
||||
def show_cursor(string = nil, &block)
|
||||
move_command("\e[?25h", string, &block)
|
||||
end
|
||||
|
||||
def hide_cursor(string = nil, &block)
|
||||
move_command("\e[?25l", string, &block)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def move_command(move, string = nil)
|
||||
if block_given?
|
||||
move << yield.to_s
|
||||
elsif string.respond_to?(:to_str)
|
||||
move << string.to_str
|
||||
elsif respond_to?(:to_str)
|
||||
move << to_str
|
||||
end
|
||||
move
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,96 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
class PPMReader
|
||||
include Term::ANSIColor
|
||||
|
||||
def initialize(io, options = {})
|
||||
@io = io
|
||||
@options = options
|
||||
@buffer = ''
|
||||
end
|
||||
|
||||
def reset_io
|
||||
begin
|
||||
@io.rewind
|
||||
rescue Errno::ESPIPE
|
||||
end
|
||||
parse_header
|
||||
end
|
||||
|
||||
def each_row
|
||||
reset_io
|
||||
@height.times do
|
||||
yield parse_row
|
||||
end
|
||||
end
|
||||
|
||||
def to_a
|
||||
enum_for(:each_row).to_a
|
||||
end
|
||||
|
||||
def to_s
|
||||
result = ''
|
||||
each_row do |row|
|
||||
last_pixel = nil
|
||||
for pixel in row
|
||||
if pixel != last_pixel
|
||||
color = Attribute.nearest_rgb_color(pixel, @options)
|
||||
result << on_color(color)
|
||||
last_pixel = pixel
|
||||
end
|
||||
result << ' '
|
||||
end
|
||||
result << reset << "\n"
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_row
|
||||
row = []
|
||||
@width.times do
|
||||
row << parse_next_pixel
|
||||
end
|
||||
row
|
||||
end
|
||||
|
||||
def parse_next_pixel
|
||||
pixel = nil
|
||||
case @type
|
||||
when 3
|
||||
@buffer.empty? and @buffer << next_line
|
||||
@buffer.sub!(/(\d+)\s+(\d+)\s+(\d+)\s*/) do
|
||||
pixel = [ $1.to_i, $2.to_i, $3.to_i ]
|
||||
''
|
||||
end
|
||||
when 6
|
||||
@buffer.size < 3 and @buffer << @io.read(8192)
|
||||
pixel = @buffer.slice!(0, 3).unpack('C3')
|
||||
end
|
||||
pixel
|
||||
end
|
||||
|
||||
def parse_header
|
||||
(line = next_line) =~ /^P([36])$/ or raise "unknown type #{line.to_s.chomp.inspect}"
|
||||
@type = $1.to_i
|
||||
|
||||
if next_line =~ /^(\d+)\s+(\d+)$/
|
||||
@width, @height = $1.to_i, $2.to_i
|
||||
else
|
||||
raise "missing dimensions"
|
||||
end
|
||||
|
||||
unless next_line =~ /^255$/
|
||||
raise "only 255 max color images allowed"
|
||||
end
|
||||
end
|
||||
|
||||
def next_line
|
||||
while line = @io.gets and line =~ /^#|^\s$/
|
||||
end
|
||||
line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,161 +0,0 @@
|
||||
module Term
|
||||
module ANSIColor
|
||||
module RGBColorMetricsHelpers
|
||||
module WeightedEuclideanDistance
|
||||
def weighted_euclidean_distance_to(other, weights = [ 1.0 ] * values.size)
|
||||
sum = 0.0
|
||||
values.zip(other.values, weights) do |s, o, w|
|
||||
sum += w * (s - o) ** 2
|
||||
end
|
||||
Math.sqrt(sum)
|
||||
end
|
||||
end
|
||||
|
||||
module NormalizeRGBTriple
|
||||
private
|
||||
|
||||
def normalize(v)
|
||||
v /= 255.0
|
||||
if v <= 0.04045
|
||||
v / 12
|
||||
else
|
||||
( (v + 0.055) / 1.055) ** 2.4
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_rgb_triple(rgb_triple)
|
||||
[
|
||||
rgb_triple.red,
|
||||
rgb_triple.green,
|
||||
rgb_triple.blue
|
||||
].map { |v| normalize(v) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module RGBColorMetrics
|
||||
def self.metric(name)
|
||||
metric?(name) or raise ArgumentError, "unknown metric #{name.inspect}"
|
||||
end
|
||||
|
||||
def self.metric?(name)
|
||||
if const_defined?(name)
|
||||
const_get name
|
||||
end
|
||||
end
|
||||
|
||||
def self.metrics
|
||||
constants.map(&:to_sym)
|
||||
end
|
||||
|
||||
# Implements color distance how the old greeks and most donkeys would…
|
||||
module Euclidean
|
||||
def self.distance(rgb1, rgb2)
|
||||
rgb1.weighted_euclidean_distance_to rgb2
|
||||
end
|
||||
end
|
||||
|
||||
# Implements color distance the best way everybody knows…
|
||||
module NTSC
|
||||
def self.distance(rgb1, rgb2)
|
||||
rgb1.weighted_euclidean_distance_to rgb2, [ 0.299, 0.587, 0.114 ]
|
||||
end
|
||||
end
|
||||
|
||||
# Implements color distance as given in:
|
||||
# http://www.compuphase.com/cmetric.htm
|
||||
module CompuPhase
|
||||
def self.distance(rgb1, rgb2)
|
||||
rmean = (rgb1.red + rgb2.red) / 2
|
||||
rgb1.weighted_euclidean_distance_to rgb2,
|
||||
[ 2 + (rmean >> 8), 4, 2 + ((255 - rmean) >> 8) ]
|
||||
end
|
||||
end
|
||||
|
||||
module YUV
|
||||
class YUVTriple < Struct.new(:y, :u, :v)
|
||||
include RGBColorMetricsHelpers::WeightedEuclideanDistance
|
||||
|
||||
def self.from_rgb_triple(rgb_triple)
|
||||
r, g, b = rgb_triple.red, rgb_triple.green, rgb_triple.blue
|
||||
y = (0.299 * r + 0.587 * g + 0.114 * b).round
|
||||
u = ((b - y) * 0.492).round
|
||||
v = ((r - y) * 0.877).round
|
||||
new(y, u, v)
|
||||
end
|
||||
end
|
||||
|
||||
def self.distance(rgb1, rgb2)
|
||||
yuv1 = YUVTriple.from_rgb_triple(rgb1)
|
||||
yuv2 = YUVTriple.from_rgb_triple(rgb2)
|
||||
yuv1.weighted_euclidean_distance_to yuv2
|
||||
end
|
||||
end
|
||||
|
||||
module CIEXYZ
|
||||
class CIEXYZTriple < Struct.new(:x, :y, :z)
|
||||
include RGBColorMetricsHelpers::WeightedEuclideanDistance
|
||||
extend RGBColorMetricsHelpers::NormalizeRGBTriple
|
||||
|
||||
def self.from_rgb_triple(rgb_triple)
|
||||
r, g, b = normalize_rgb_triple rgb_triple
|
||||
|
||||
x = 0.436052025 * r + 0.385081593 * g + 0.143087414 * b
|
||||
y = 0.222491598 * r + 0.71688606 * g + 0.060621486 * b
|
||||
z = 0.013929122 * r + 0.097097002 * g + 0.71418547 * b
|
||||
|
||||
x *= 255
|
||||
y *= 255
|
||||
z *= 255
|
||||
|
||||
new(x.round, y.round, z.round)
|
||||
end
|
||||
end
|
||||
|
||||
def self.distance(rgb1, rgb2)
|
||||
xyz1 = CIEXYZTriple.from_rgb_triple(rgb1)
|
||||
xyz2 = CIEXYZTriple.from_rgb_triple(rgb2)
|
||||
xyz1.weighted_euclidean_distance_to xyz2
|
||||
end
|
||||
end
|
||||
|
||||
module CIELab
|
||||
class CIELabTriple < Struct.new(:l, :a, :b)
|
||||
include RGBColorMetricsHelpers::WeightedEuclideanDistance
|
||||
extend RGBColorMetricsHelpers::NormalizeRGBTriple
|
||||
|
||||
def self.from_rgb_triple(rgb_triple)
|
||||
r, g, b = normalize_rgb_triple rgb_triple
|
||||
|
||||
x = 0.436052025 * r + 0.385081593 * g + 0.143087414 * b
|
||||
y = 0.222491598 * r + 0.71688606 * g + 0.060621486 * b
|
||||
z = 0.013929122 * r + 0.097097002 * g + 0.71418547 * b
|
||||
|
||||
xr = x / 0.964221
|
||||
yr = y
|
||||
zr = z / 0.825211
|
||||
|
||||
eps = 216.0 / 24389
|
||||
k = 24389.0 / 27
|
||||
|
||||
fx = xr > eps ? xr ** (1.0 / 3) : (k * xr + 16) / 116
|
||||
fy = yr > eps ? yr ** (1.0 / 3) : (k * yr + 16) / 116
|
||||
fz = zr > eps ? zr ** (1.0 / 3) : (k * zr + 16) / 116
|
||||
|
||||
l = 2.55 * ((116 * fy) - 16)
|
||||
a = 500 * (fx - fy)
|
||||
b = 200 * (fy - fz)
|
||||
|
||||
new(l.round, a.round, b.round)
|
||||
end
|
||||
end
|
||||
|
||||
def self.distance(rgb1, rgb2)
|
||||
lab1 = CIELabTriple.from_rgb_triple(rgb1)
|
||||
lab2 = CIELabTriple.from_rgb_triple(rgb2)
|
||||
lab1.weighted_euclidean_distance_to lab2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,179 +0,0 @@
|
||||
require 'term/ansicolor/rgb_color_metrics'
|
||||
|
||||
module Term
|
||||
module ANSIColor
|
||||
class RGBTriple
|
||||
include Term::ANSIColor::RGBColorMetricsHelpers::WeightedEuclideanDistance
|
||||
|
||||
def self.convert_value(color, max: 255)
|
||||
color.nil? and raise ArgumentError, "missing color value"
|
||||
color = Integer(color)
|
||||
(0..max) === color or raise ArgumentError,
|
||||
"color value #{color.inspect} not between 0 and #{max}"
|
||||
color
|
||||
end
|
||||
|
||||
private_class_method :convert_value
|
||||
|
||||
def self.from_html(html)
|
||||
case html
|
||||
when /\A#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})\z/i
|
||||
new(*$~.captures.map { |c| convert_value(c.to_i(16)) })
|
||||
when /\A#([0-9a-f])([0-9a-f])([0-9a-f])\z/i
|
||||
new(*$~.captures.map { |c| convert_value((c + c).to_i(16)) })
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_css(css)
|
||||
case css
|
||||
when /\A\s*rgb\(\s*([^%\s]+)\s*%\s*,\s*([^%\s]+)\s*%\s*,\s*([^%\s]+)\s*%\s*\)\z/
|
||||
new(*$~.captures.map { |c| convert_value(((Float(c) / 100) * 0xff).round) })
|
||||
when /\A\s*rgb\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^\)\s]+)\s*\)\z/
|
||||
new(*$~.captures.map { |c| convert_value((Float(c)).round) })
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_hash(options)
|
||||
new(
|
||||
convert_value(options[:red]),
|
||||
convert_value(options[:green]),
|
||||
convert_value(options[:blue])
|
||||
)
|
||||
end
|
||||
|
||||
def self.from_array(array)
|
||||
new(*array)
|
||||
end
|
||||
|
||||
def self.[](thing)
|
||||
case
|
||||
when thing.respond_to?(:to_rgb_triple) then thing.to_rgb_triple
|
||||
when thing.respond_to?(:to_ary) then from_array(thing.to_ary)
|
||||
when thing.respond_to?(:to_str)
|
||||
thing = thing.to_str
|
||||
from_html(thing.sub(/\Aon_/, '')) || from_css(thing) ||
|
||||
Term::ANSIColor::HSLTriple.from_css(thing).full?(:to_rgb_triple)
|
||||
when thing.respond_to?(:to_hash) then from_hash(thing.to_hash)
|
||||
else raise ArgumentError, "cannot convert #{thing.inspect} into #{self}"
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(red, green, blue)
|
||||
@values = [ red, green, blue ].map { |v|
|
||||
[ [ Integer(v), 0 ].max, 0xff ].min
|
||||
}
|
||||
end
|
||||
|
||||
def red
|
||||
@values[0]
|
||||
end
|
||||
|
||||
def green
|
||||
@values[1]
|
||||
end
|
||||
|
||||
def blue
|
||||
@values[2]
|
||||
end
|
||||
|
||||
def percentages
|
||||
@percentages ||= @values.map { |v| 100 * v / 255.0 }
|
||||
end
|
||||
|
||||
def red_p
|
||||
percentages[0]
|
||||
end
|
||||
|
||||
def green_p
|
||||
percentages[1]
|
||||
end
|
||||
|
||||
def blue_p
|
||||
percentages[2]
|
||||
end
|
||||
|
||||
def invert
|
||||
self.class.new(255 - red, 255 - green, 255 - blue)
|
||||
end
|
||||
|
||||
def gray?
|
||||
red != 0 && red != 0xff && red == green && green == blue && blue == red
|
||||
end
|
||||
|
||||
def html
|
||||
s = '#'
|
||||
@values.each { |c| s << '%02x' % c }
|
||||
s
|
||||
end
|
||||
|
||||
def css(percentage: false)
|
||||
if percentage
|
||||
"rgb(%s%%,%s%%,%s%%)" % @values.map { |v| 100.0 * v / 255 }
|
||||
else
|
||||
"rgb(%u,%u,%u)" % @values
|
||||
end
|
||||
end
|
||||
|
||||
def to_rgb_triple
|
||||
self
|
||||
end
|
||||
|
||||
def to_hsl_triple
|
||||
Term::ANSIColor::HSLTriple.from_rgb_triple(self)
|
||||
end
|
||||
|
||||
attr_reader :values
|
||||
protected :values
|
||||
|
||||
def to_a
|
||||
@values.dup
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
@values == other.to_rgb_triple.values
|
||||
end
|
||||
|
||||
def color(string)
|
||||
Term::ANSIColor.color(self, string)
|
||||
end
|
||||
|
||||
def distance_to(other, options = {})
|
||||
options[:metric] ||= RGBColorMetrics::CIELab
|
||||
options[:metric].distance(self, other)
|
||||
end
|
||||
|
||||
def initialize_copy(other)
|
||||
r = super
|
||||
other.instance_variable_set :@values, @values.dup
|
||||
r
|
||||
end
|
||||
|
||||
def gradient_to(other, options = {})
|
||||
options[:steps] ||= 16
|
||||
steps = options[:steps].to_i
|
||||
steps < 2 and raise ArgumentError, 'at least 2 steps are required'
|
||||
changes = other.values.zip(@values).map { |x, y| x - y }
|
||||
current = self
|
||||
gradient = [ current.dup ]
|
||||
s = steps - 1
|
||||
while s > 1
|
||||
current = current.dup
|
||||
gradient << current
|
||||
3.times do |i|
|
||||
current.values[i] += changes[i] / (steps - 1)
|
||||
end
|
||||
s -= 1
|
||||
end
|
||||
gradient << other
|
||||
end
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
if Term::ANSIColor::HSLTriple.method_defined?(name)
|
||||
to_hsl_triple.send(name, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,8 +0,0 @@
|
||||
module Term::ANSIColor
|
||||
# Term::ANSIColor version
|
||||
VERSION = '1.7.1'
|
||||
VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
|
||||
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
|
||||
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
|
||||
VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
|
||||
end
|
@ -1,2 +0,0 @@
|
||||
require 'tins/alias'
|
||||
require 'tins/dslkit/polite'
|
@ -1 +0,0 @@
|
||||
require 'tins/dslkit'
|
@ -1 +0,0 @@
|
||||
require 'tins/xt/dslkit'
|
@ -1,2 +0,0 @@
|
||||
require 'tins'
|
||||
require 'tins/alias'
|
@ -1,61 +0,0 @@
|
||||
module Tins
|
||||
require 'tins/attempt'
|
||||
require 'tins/bijection'
|
||||
require 'tins/count_by'
|
||||
require 'tins/deep_dup'
|
||||
require 'tins/file_binary'
|
||||
require 'tins/find'
|
||||
require 'tins/generator'
|
||||
require 'tins/go'
|
||||
require 'tins/hash_symbolize_keys_recursive'
|
||||
require 'tins/hash_union'
|
||||
require 'tins/limited'
|
||||
require 'tins/lines_file'
|
||||
require 'tins/memoize'
|
||||
require 'tins/minimize'
|
||||
require 'tins/module_group'
|
||||
require 'tins/named_set'
|
||||
require 'tins/null'
|
||||
require 'tins/once'
|
||||
require 'tins/p'
|
||||
require 'tins/partial_application'
|
||||
require 'tins/range_plus'
|
||||
require 'tins/require_maybe'
|
||||
require 'tins/secure_write'
|
||||
require 'tins/string_camelize'
|
||||
require 'tins/string_underscore'
|
||||
require 'tins/string_version'
|
||||
require 'tins/subhash'
|
||||
require 'tins/time_dummy'
|
||||
require 'tins/date_dummy'
|
||||
require 'tins/date_time_dummy'
|
||||
require 'tins/to_proc'
|
||||
require 'tins/uniq_by'
|
||||
require 'tins/version'
|
||||
require 'tins/write'
|
||||
require 'tins/extract_last_argument_options'
|
||||
require 'tins/deep_const_get'
|
||||
require 'tins/responding'
|
||||
require 'tins/proc_compose'
|
||||
require 'tins/proc_prelude'
|
||||
require 'tins/concern'
|
||||
require 'tins/to'
|
||||
require 'tins/terminal'
|
||||
require 'tins/sexy_singleton'
|
||||
require 'tins/method_description'
|
||||
require 'tins/annotate'
|
||||
require 'tins/token'
|
||||
require 'tins/dslkit'
|
||||
require 'tins/case_predicate'
|
||||
require 'tins/implement'
|
||||
if defined? ::Encoding
|
||||
require 'tins/string_byte_order_mark'
|
||||
end
|
||||
require 'tins/complete'
|
||||
require 'tins/duration'
|
||||
require 'tins/unit'
|
||||
require 'tins/expose'
|
||||
require 'tins/temp_io'
|
||||
require 'tins/temp_io_enum'
|
||||
end
|
||||
require 'tins/alias'
|
@ -1 +0,0 @@
|
||||
Spruz = Tins
|
@ -1,38 +0,0 @@
|
||||
module Tins::Annotate
|
||||
def annotate(name)
|
||||
singleton_class.class_eval do
|
||||
define_method(name) do |annotation = :annotated|
|
||||
instance_variable_set "@__annotation_#{name}__", annotation
|
||||
end
|
||||
|
||||
define_method("#{name}_of") do |method_name|
|
||||
__send__("#{name}_annotations")[method_name]
|
||||
end
|
||||
|
||||
define_method("#{name}_annotations") do
|
||||
if instance_variable_defined?("@__annotation_#{name}_annotations__")
|
||||
instance_variable_get "@__annotation_#{name}_annotations__"
|
||||
else
|
||||
instance_variable_set "@__annotation_#{name}_annotations__", {}
|
||||
end
|
||||
end
|
||||
|
||||
old_method_added = instance_method(:method_added)
|
||||
define_method(:method_added) do |method_name|
|
||||
old_method_added.bind(self).call method_name
|
||||
if annotation = instance_variable_get("@__annotation_#{name}__")
|
||||
__send__("#{name}_annotations")[method_name] = annotation
|
||||
end
|
||||
instance_variable_set "@__annotation_#{name}__", nil
|
||||
end
|
||||
end
|
||||
|
||||
define_method("#{name}_annotations") do
|
||||
self.class.__send__("#{name}_annotations")
|
||||
end
|
||||
|
||||
define_method("#{name}_of") do |method_name|
|
||||
self.class.__send__("#{name}_of", method_name)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,31 +0,0 @@
|
||||
module Tins
|
||||
module AskAndSend
|
||||
def ask_and_send(method_name, *args, &block)
|
||||
if respond_to?(method_name)
|
||||
__send__(method_name, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def ask_and_send!(method_name, *args, &block)
|
||||
if respond_to?(method_name, true)
|
||||
__send__(method_name, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def ask_and_send_or_self(method_name, *args, &block)
|
||||
if respond_to?(method_name)
|
||||
__send__(method_name, *args, &block)
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
def ask_and_send_or_self!(method_name, *args, &block)
|
||||
if respond_to?(method_name, true)
|
||||
__send__(method_name, *args, &block)
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,111 +0,0 @@
|
||||
module Tins
|
||||
module Attempt
|
||||
# Attempts code in block *attempts* times, sleeping according to *sleep*
|
||||
# between attempts and catching the exception(s) in *exception_class*.
|
||||
#
|
||||
# *sleep* is either a Proc returning a floating point number for duration
|
||||
# as seconds or a Numeric >= 0 or < 0. In the former case this is the
|
||||
# duration directly, in the latter case -*sleep* is the total number of
|
||||
# seconds that is slept before giving up, and every attempt is retried
|
||||
# after a exponentially increasing duration of seconds.
|
||||
#
|
||||
# Iff *reraise* is true the caught exception is reraised after running out
|
||||
# of attempts.
|
||||
def attempt(opts = {}, &block)
|
||||
sleep = nil
|
||||
exception_class = StandardError
|
||||
if Numeric === opts
|
||||
attempts = opts
|
||||
else
|
||||
attempts = opts[:attempts] || 1
|
||||
attempts >= 1 or raise ArgumentError, 'at least one attempt is required'
|
||||
exception_class = opts[:exception_class] if opts.key?(:exception_class)
|
||||
sleep = interpret_sleep(opts[:sleep], attempts)
|
||||
reraise = opts[:reraise]
|
||||
end
|
||||
return if attempts <= 0
|
||||
count = 0
|
||||
if exception_class.nil?
|
||||
begin
|
||||
count += 1
|
||||
if block.call(count)
|
||||
return true
|
||||
elsif count < attempts
|
||||
sleep_duration(sleep, count)
|
||||
end
|
||||
end until count == attempts
|
||||
false
|
||||
else
|
||||
begin
|
||||
count += 1
|
||||
block.call(count)
|
||||
true
|
||||
rescue *exception_class
|
||||
if count < attempts
|
||||
sleep_duration(sleep, count)
|
||||
retry
|
||||
end
|
||||
reraise ? raise : false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sleep_duration(duration, count)
|
||||
case duration
|
||||
when Numeric
|
||||
sleep duration
|
||||
when Proc
|
||||
sleep duration.call(count)
|
||||
end
|
||||
end
|
||||
|
||||
def compute_duration_base(sleep, attempts)
|
||||
x1, x2 = 1, sleep
|
||||
attempts <= sleep or raise ArgumentError,
|
||||
"need less or equal number of attempts than sleep duration #{sleep}"
|
||||
x1 >= x2 and raise ArgumentError, "invalid sleep argument: #{sleep.inspect}"
|
||||
function = -> x { (0...attempts).inject { |s, i| s + x ** i } - sleep }
|
||||
f, fmid = function[x1], function[x2]
|
||||
f * fmid >= 0 and raise ArgumentError, "invalid sleep argument: #{sleep.inspect}"
|
||||
n = 1 << 16
|
||||
epsilon = 1E-16
|
||||
root = if f < 0
|
||||
dx = x2 - x1
|
||||
x1
|
||||
else
|
||||
dx = x1 - x2
|
||||
x2
|
||||
end
|
||||
n.times do
|
||||
fmid = function[xmid = root + (dx *= 0.5)]
|
||||
fmid < 0 and root = xmid
|
||||
dx.abs < epsilon or fmid == 0 and return root
|
||||
end
|
||||
raise ArgumentError, "too many iterations (#{n})"
|
||||
result
|
||||
end
|
||||
|
||||
def interpret_sleep(sleep, attempts)
|
||||
case sleep
|
||||
when nil
|
||||
when Numeric
|
||||
if sleep < 0
|
||||
if attempts > 2
|
||||
sleep = -sleep
|
||||
duration_base = compute_duration_base sleep, attempts
|
||||
sleep = lambda { |i| duration_base ** i }
|
||||
else
|
||||
raise ArgumentError, "require > 2 attempts for negative sleep value"
|
||||
end
|
||||
end
|
||||
sleep
|
||||
when Proc
|
||||
sleep
|
||||
else
|
||||
raise TypeError, "require Proc or Numeric sleep argument"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,46 +0,0 @@
|
||||
module Tins
|
||||
class Bijection < Hash
|
||||
def self.[](*pairs)
|
||||
pairs.size % 2 == 0 or
|
||||
raise ArgumentError, "odd number of arguments for #{self}"
|
||||
new.fill do |obj|
|
||||
(pairs.size / 2).times do |i|
|
||||
j = 2 * i
|
||||
key = pairs[j]
|
||||
value = pairs[j + 1]
|
||||
obj.key?(key) and raise ArgumentError, "duplicate key #{key.inspect} for #{self}"
|
||||
obj.inverted.key?(value) and raise ArgumentError, "duplicate value #{value.inspect} for #{self}"
|
||||
obj[pairs[j]] = pairs[j + 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(inverted = Bijection.new(self))
|
||||
@inverted = inverted
|
||||
end
|
||||
|
||||
def fill
|
||||
if empty?
|
||||
yield self
|
||||
freeze
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def freeze
|
||||
r = super
|
||||
unless @inverted.frozen?
|
||||
@inverted.freeze
|
||||
end
|
||||
r
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
key?(key) and return
|
||||
super
|
||||
@inverted[value] = key
|
||||
end
|
||||
|
||||
attr_reader :inverted
|
||||
end
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
module Tins
|
||||
module CasePredicate
|
||||
def case?(*args)
|
||||
args.find { |a| a === self }
|
||||
end
|
||||
end
|
||||
end
|
@ -1,18 +0,0 @@
|
||||
require 'readline'
|
||||
|
||||
module Tins
|
||||
module Complete
|
||||
module_function
|
||||
|
||||
@@sync = Sync.new
|
||||
|
||||
def complete(prompt: '', add_hist: false, &block)
|
||||
@@sync.synchronize do
|
||||
Readline.completion_proc = block
|
||||
Readline.input = STDIN
|
||||
Readline.output = STDOUT
|
||||
Readline.readline(prompt, add_hist)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,30 +0,0 @@
|
||||
module Tins
|
||||
module Concern
|
||||
def self.extended(base)
|
||||
base.instance_variable_set("@_dependencies", [])
|
||||
end
|
||||
|
||||
def append_features(base)
|
||||
if base.instance_variable_defined?("@_dependencies")
|
||||
base.instance_variable_get("@_dependencies") << self
|
||||
false
|
||||
else
|
||||
return false if base < self
|
||||
@_dependencies.each { |dep| base.send(:include, dep) }
|
||||
super
|
||||
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
|
||||
base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
|
||||
Thread.current[:tin_concern_args] = nil
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def included(base = nil, &block)
|
||||
if base.nil?
|
||||
@_included_block = block
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,8 +0,0 @@
|
||||
module Tins
|
||||
module CountBy
|
||||
def count_by(&b)
|
||||
b ||= lambda { |x| true }
|
||||
inject(0) { |s, e| s += 1 if b[e]; s }
|
||||
end
|
||||
end
|
||||
end
|
@ -1,53 +0,0 @@
|
||||
require 'date'
|
||||
|
||||
module Tins
|
||||
module DateDummy
|
||||
def self.included(modul)
|
||||
class << modul
|
||||
alias really_today today
|
||||
|
||||
remove_method :today rescue nil
|
||||
|
||||
def dummy=(value)
|
||||
if value.respond_to?(:to_str)
|
||||
value = Date.parse(value.to_str)
|
||||
elsif value.respond_to?(:to_date)
|
||||
value = value.to_date
|
||||
end
|
||||
@dummy = value
|
||||
end
|
||||
|
||||
def dummy(value = nil)
|
||||
if value.nil?
|
||||
if defined?(@dummy)
|
||||
@dummy
|
||||
end
|
||||
else
|
||||
begin
|
||||
old_dummy = @dummy
|
||||
self.dummy = value
|
||||
yield
|
||||
ensure
|
||||
self.dummy = old_dummy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def today
|
||||
if dummy
|
||||
dummy.dup
|
||||
elsif caller.first =~ /`today`/
|
||||
really_today
|
||||
else
|
||||
really_today
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
||||
|
@ -1,51 +0,0 @@
|
||||
require 'date'
|
||||
|
||||
module Tins
|
||||
module DateTimeDummy
|
||||
def self.included(modul)
|
||||
class << modul
|
||||
alias really_now now
|
||||
|
||||
remove_method :now rescue nil
|
||||
|
||||
def dummy=(value)
|
||||
if value.respond_to?(:to_str)
|
||||
value = DateTime.parse(value.to_str)
|
||||
elsif value.respond_to?(:to_datetime)
|
||||
value = value.to_datetime
|
||||
end
|
||||
@dummy = value
|
||||
end
|
||||
|
||||
def dummy(value = nil)
|
||||
if value.nil?
|
||||
if defined?(@dummy)
|
||||
@dummy
|
||||
end
|
||||
else
|
||||
begin
|
||||
old_dummy = @dummy
|
||||
self.dummy = value
|
||||
yield
|
||||
ensure
|
||||
self.dummy = old_dummy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def now
|
||||
if dummy
|
||||
dummy.dup
|
||||
elsif caller.first =~ /`now`/
|
||||
really_now
|
||||
else
|
||||
really_now
|
||||
end
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,42 +0,0 @@
|
||||
module Tins
|
||||
module DeepConstGet
|
||||
if ::Object.method(:const_defined?).arity == 1
|
||||
# :nocov:
|
||||
# We do not create coverage on 1.8
|
||||
def self.const_defined_in?(modul, constant)
|
||||
modul.const_defined?(constant)
|
||||
end
|
||||
# :nocov:
|
||||
else
|
||||
def self.const_defined_in?(modul, constant)
|
||||
modul.const_defined?(constant, false)
|
||||
end
|
||||
end
|
||||
|
||||
def self.deep_const_get(path, start_module = Object)
|
||||
path.to_s.split('::').inject(start_module) do |p, c|
|
||||
case
|
||||
when c.empty?
|
||||
if start_module == Object
|
||||
Object
|
||||
else
|
||||
raise ArgumentError, "top level constants cannot be reached from"\
|
||||
" start module #{start_module.inspect}"
|
||||
end
|
||||
when const_defined_in?(p, c)
|
||||
p.const_get(c)
|
||||
else
|
||||
begin
|
||||
p.const_missing(c)
|
||||
rescue NameError => e
|
||||
raise ArgumentError, "can't get const #{path}: #{e}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def deep_const_get(path, start_module = Object)
|
||||
::Tins::DeepConstGet.deep_const_get(path, start_module)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
module Tins
|
||||
module DeepDup
|
||||
def deep_dup
|
||||
Marshal.load(Marshal.dump(self))
|
||||
rescue TypeError
|
||||
return self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,636 +0,0 @@
|
||||
require 'thread'
|
||||
require 'sync'
|
||||
|
||||
require 'tins/thread_local'
|
||||
|
||||
module Tins
|
||||
# This module contains some handy methods to deal with eigenclasses. Those
|
||||
# are also known as virtual classes, singleton classes, metaclasses, plus all
|
||||
# the other names Matz doesn't like enough to actually accept one of the
|
||||
# names.
|
||||
#
|
||||
# The module can be included into other modules/classes to make the methods available.
|
||||
module Eigenclass
|
||||
# Returns the eigenclass of this object.
|
||||
def eigenclass
|
||||
end
|
||||
alias eigenclass singleton_class
|
||||
|
||||
# Evaluates the _block_ in context of the eigenclass of this object.
|
||||
def eigenclass_eval(&block)
|
||||
eigenclass.instance_eval(&block)
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethod
|
||||
include Eigenclass
|
||||
|
||||
# Define a class method named _name_ using _block_.
|
||||
def class_define_method(name, &block)
|
||||
eigenclass_eval { define_method(name, &block) }
|
||||
end
|
||||
|
||||
# Define reader and writer attribute methods for all <i>*ids</i>.
|
||||
def class_attr_accessor(*ids)
|
||||
eigenclass_eval { attr_accessor(*ids) }
|
||||
end
|
||||
|
||||
# Define reader attribute methods for all <i>*ids</i>.
|
||||
def class_attr_reader(*ids)
|
||||
eigenclass_eval { attr_reader(*ids) }
|
||||
end
|
||||
|
||||
# Define writer attribute methods for all <i>*ids</i>.
|
||||
def class_attr_writer(*ids)
|
||||
eigenclass_eval { attr_writer(*ids) }
|
||||
end
|
||||
|
||||
# I boycott attr!
|
||||
end
|
||||
|
||||
module ThreadGlobal
|
||||
# Define a thread global variable named _name_ in this module/class. If the
|
||||
# value _value_ is given, it is used to initialize the variable.
|
||||
def thread_global(name, default_value = nil, &default)
|
||||
is_a?(Module) or raise TypeError, "receiver has to be a Module"
|
||||
|
||||
default_value && default and raise ArgumentError,
|
||||
"require either default_falue or default block"
|
||||
|
||||
if default_value
|
||||
default = -> * { default_value }
|
||||
end
|
||||
|
||||
name = name.to_s
|
||||
var_name = "@__#{name}_#{__id__.abs}__"
|
||||
|
||||
lock = Mutex.new
|
||||
modul = self
|
||||
|
||||
define_method(name) do
|
||||
lock.synchronize {
|
||||
if default && !modul.instance_variable_defined?(var_name)
|
||||
modul.instance_variable_set var_name, default.call
|
||||
end
|
||||
modul.instance_variable_get var_name
|
||||
}
|
||||
end
|
||||
|
||||
define_method(name + "=") do |value|
|
||||
lock.synchronize { modul.instance_variable_set var_name, value }
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Define a thread global variable for the current instance with name
|
||||
# _name_. If the value _value_ is given, it is used to initialize the
|
||||
# variable.
|
||||
def instance_thread_global(name, value = nil)
|
||||
sc = class << self
|
||||
extend Tins::ThreadGlobal
|
||||
self
|
||||
end
|
||||
sc.thread_global name, value
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceExec
|
||||
def self.included(*)
|
||||
super
|
||||
warn "#{self} is deprecated, but included at #{caller.first[/(.*):/, 1]}"
|
||||
end
|
||||
end
|
||||
|
||||
module Interpreter
|
||||
# Interpret the string _source_ as a body of a block, while passing
|
||||
# <i>*args</i> into the block.
|
||||
#
|
||||
# A small example explains how the method is supposed to be used and how
|
||||
# the <i>*args</i> can be fetched:
|
||||
#
|
||||
# class A
|
||||
# include Tins::Interpreter
|
||||
# def c
|
||||
# 3
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# A.new.interpret('|a,b| a + b + c', 1, 2) # => 6
|
||||
#
|
||||
# To use a specified binding see #interpret_with_binding.
|
||||
def interpret(source, *args)
|
||||
interpret_with_binding(source, binding, *args)
|
||||
end
|
||||
|
||||
# Interpret the string _source_ as a body of a block, while passing
|
||||
# <i>*args</i> into the block and using _my_binding_ for evaluation.
|
||||
#
|
||||
# A small example:
|
||||
#
|
||||
# class A
|
||||
# include Tins::Interpreter
|
||||
# def c
|
||||
# 3
|
||||
# end
|
||||
# def foo
|
||||
# b = 2
|
||||
# interpret_with_binding('|a| a + b + c', binding, 1) # => 6
|
||||
# end
|
||||
# end
|
||||
# A.new.foo # => 6
|
||||
#
|
||||
# See also #interpret.
|
||||
def interpret_with_binding(source, my_binding, *args)
|
||||
path = '(interpret)'
|
||||
if source.respond_to? :to_io
|
||||
path = source.path if source.respond_to? :path
|
||||
source = source.to_io.read
|
||||
end
|
||||
block = lambda { |*a| eval("lambda { #{source} }", my_binding, path).call(*a) }
|
||||
instance_exec(*args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
# This module contains the _constant_ method. For small example of its usage
|
||||
# see the documentation of the DSLAccessor module.
|
||||
module Constant
|
||||
# Create a constant named _name_, that refers to value _value_. _value is
|
||||
# frozen, if this is possible. If you want to modify/exchange a value use
|
||||
# DSLAccessor#dsl_reader/DSLAccessor#dsl_accessor instead.
|
||||
def constant(name, value = name)
|
||||
value = value.freeze rescue value
|
||||
define_method(name) { value }
|
||||
end
|
||||
end
|
||||
|
||||
# The DSLAccessor module contains some methods, that can be used to make
|
||||
# simple accessors for a DSL.
|
||||
#
|
||||
#
|
||||
# class CoffeeMaker
|
||||
# extend Tins::Constant
|
||||
#
|
||||
# constant :on
|
||||
# constant :off
|
||||
#
|
||||
# extend Tins::DSLAccessor
|
||||
#
|
||||
# dsl_accessor(:state) { off } # Note: the off constant from above is used
|
||||
#
|
||||
# dsl_accessor :allowed_states, :on, :off
|
||||
#
|
||||
# def process
|
||||
# allowed_states.include?(state) or fail "Explode!!!"
|
||||
# if state == on
|
||||
# puts "Make coffee."
|
||||
# else
|
||||
# puts "Idle..."
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# cm = CoffeeMaker.new
|
||||
# cm.instance_eval do
|
||||
# state # => :off
|
||||
# state on
|
||||
# state # => :on
|
||||
# process # => outputs "Make coffee."
|
||||
# end
|
||||
#
|
||||
# Note that Tins::SymbolMaker is an alternative for Tins::Constant in
|
||||
# this example. On the other hand SymbolMaker can make debugging more
|
||||
# difficult.
|
||||
module DSLAccessor
|
||||
# This method creates a dsl accessor named _name_. If nothing else is given
|
||||
# as argument it defaults to nil. If <i>*default</i> is given as a single
|
||||
# value it is used as a default value, if more than one value is given the
|
||||
# _default_ array is used as the default value. If no default value but a
|
||||
# block _block_ is given as an argument, the block is executed everytime
|
||||
# the accessor is read <b>in the context of the current instance</b>.
|
||||
#
|
||||
# After setting up the accessor, the set or default value can be retrieved
|
||||
# by calling the method +name+. To set a value one can call <code>name
|
||||
# :foo</code> to set the attribute value to <code>:foo</code> or
|
||||
# <code>name(:foo, :bar)</code> to set it to <code>[ :foo, :bar ]</code>.
|
||||
def dsl_accessor(name, *default, &block)
|
||||
variable = "@#{name}"
|
||||
define_method(name) do |*args|
|
||||
if args.empty?
|
||||
result =
|
||||
if instance_variable_defined?(variable)
|
||||
instance_variable_get(variable)
|
||||
end
|
||||
if result.nil?
|
||||
result = if default.empty?
|
||||
block && instance_eval(&block)
|
||||
elsif default.size == 1
|
||||
default.first
|
||||
else
|
||||
default
|
||||
end
|
||||
instance_variable_set(variable, result)
|
||||
result
|
||||
else
|
||||
result
|
||||
end
|
||||
else
|
||||
instance_variable_set(variable, args.size == 1 ? args.first : args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This method creates a dsl reader accessor, that behaves exactly like a
|
||||
# #dsl_accessor but can only be read not set.
|
||||
def dsl_reader(name, *default, &block)
|
||||
variable = "@#{name}"
|
||||
define_method(name) do |*args|
|
||||
if args.empty?
|
||||
result =
|
||||
if instance_variable_defined?(variable)
|
||||
instance_variable_get(variable)
|
||||
end
|
||||
if result.nil?
|
||||
if default.empty?
|
||||
block && instance_eval(&block)
|
||||
elsif default.size == 1
|
||||
default.first
|
||||
else
|
||||
default
|
||||
end
|
||||
else
|
||||
result
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This module can be included in another module/class. It generates a symbol
|
||||
# for every missing method that was called in the context of this
|
||||
# module/class.
|
||||
module SymbolMaker
|
||||
# Returns a symbol (_id_) for every missing method named _id_.
|
||||
def method_missing(id, *args)
|
||||
if args.empty?
|
||||
id
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This module can be used to extend another module/class. It generates
|
||||
# symbols for every missing constant under the namespace of this
|
||||
# module/class.
|
||||
module ConstantMaker
|
||||
# Returns a symbol (_id_) for every missing constant named _id_.
|
||||
def const_missing(id)
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
module BlankSlate
|
||||
# Creates an anonymous blank slate class, that only responds to the methods
|
||||
# <i>*ids</i>. ids can be Symbols, Strings, and Regexps that have to match
|
||||
# the method name with #===.
|
||||
def self.with(*ids)
|
||||
opts = Hash === ids.last ? ids.pop : {}
|
||||
ids = ids.map { |id| Regexp === id ? id : id.to_s }
|
||||
klass = opts[:superclass] ? Class.new(opts[:superclass]) : Class.new
|
||||
klass.instance_eval do
|
||||
instance_methods.each do |m|
|
||||
m = m.to_s
|
||||
undef_method m unless m =~ /^(__|object_id)/ or ids.any? { |i| i === m }
|
||||
end
|
||||
end
|
||||
klass
|
||||
end
|
||||
end
|
||||
|
||||
# See examples/recipe.rb and examples/recipe2.rb how this works at the
|
||||
# moment.
|
||||
module Deflect
|
||||
# The basic Deflect exception
|
||||
class DeflectError < StandardError; end
|
||||
|
||||
class << self
|
||||
extend Tins::ThreadLocal
|
||||
|
||||
# A thread local variable, that holds a DeflectorCollection instance for
|
||||
# the current thread.
|
||||
thread_local :deflecting
|
||||
end
|
||||
|
||||
# A deflector is called with a _class_, a method _id_, and its
|
||||
# <i>*args</i>.
|
||||
class Deflector < Proc; end
|
||||
|
||||
# This class implements a collection of deflectors, to make them available
|
||||
# by emulating Ruby's message dispatch.
|
||||
class DeflectorCollection
|
||||
def initialize
|
||||
@classes = {}
|
||||
end
|
||||
|
||||
# Add a new deflector _deflector_ for class _klass_ and method name _id_,
|
||||
# and return self.
|
||||
#
|
||||
def add(klass, id, deflector)
|
||||
k = @classes[klass]
|
||||
k = @classes[klass] = {} unless k
|
||||
k[id.to_s] = deflector
|
||||
self
|
||||
end
|
||||
|
||||
# Return true if messages are deflected for class _klass_ and method name
|
||||
# _id_, otherwise return false.
|
||||
def member?(klass, id)
|
||||
!!(k = @classes[klass] and k.key?(id.to_s))
|
||||
end
|
||||
|
||||
# Delete the deflecotor class _klass_ and method name _id_. Returns the
|
||||
# deflector if any was found, otherwise returns true.
|
||||
def delete(klass, id)
|
||||
if k = @classes[klass]
|
||||
d = k.delete id.to_s
|
||||
@classes.delete klass if k.empty?
|
||||
d
|
||||
end
|
||||
end
|
||||
|
||||
# Try to find a deflector for class _klass_ and method _id_ and return
|
||||
# it. If none was found, return nil instead.
|
||||
def find(klass, id)
|
||||
klass.ancestors.find do |k|
|
||||
if d = @classes[k] and d = d[id.to_s]
|
||||
return d
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@sync = Sync.new
|
||||
|
||||
# Start deflecting method calls named _id_ to the _from_ class using the
|
||||
# Deflector instance deflector.
|
||||
def deflect_start(from, id, deflector)
|
||||
@@sync.synchronize do
|
||||
Deflect.deflecting ||= DeflectorCollection.new
|
||||
Deflect.deflecting.member?(from, id) and
|
||||
raise DeflectError, "#{from}##{id} is already deflected"
|
||||
Deflect.deflecting.add(from, id, deflector)
|
||||
from.class_eval do
|
||||
define_method(id) do |*args|
|
||||
if Deflect.deflecting and d = Deflect.deflecting.find(self.class, id)
|
||||
d.call(self, id, *args)
|
||||
else
|
||||
super(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Return true if method _id_ is deflected from class _from_, otherwise
|
||||
# return false.
|
||||
def self.deflect?(from, id)
|
||||
Deflect.deflecting && Deflect.deflecting.member?(from, id)
|
||||
end
|
||||
|
||||
# Return true if method _id_ is deflected from class _from_, otherwise
|
||||
# return false.
|
||||
def deflect?(from, id)
|
||||
Deflect.deflect?(from, id)
|
||||
end
|
||||
|
||||
# Start deflecting method calls named _id_ to the _from_ class using the
|
||||
# Deflector instance deflector. After that yield to the given block and
|
||||
# stop deflecting again.
|
||||
def deflect(from, id, deflector)
|
||||
@@sync.synchronize do
|
||||
begin
|
||||
deflect_start(from, id, deflector)
|
||||
yield
|
||||
ensure
|
||||
deflect_stop(from, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Stop deflection method calls named _id_ to class _from_.
|
||||
def deflect_stop(from, id)
|
||||
@@sync.synchronize do
|
||||
Deflect.deflecting.delete(from, id) or
|
||||
raise DeflectError, "#{from}##{id} is not deflected from"
|
||||
from.instance_eval { remove_method id }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This module can be included into modules/classes to make the delegate
|
||||
# method available.
|
||||
module Delegate
|
||||
UNSET = Object.new
|
||||
|
||||
# A method to easily delegate methods to an object, stored in an
|
||||
# instance variable or returned by a method call.
|
||||
#
|
||||
# It's used like this:
|
||||
# class A
|
||||
# delegate :method_here, :@obj, :method_there
|
||||
# end
|
||||
# or:
|
||||
# class A
|
||||
# delegate :method_here, :method_call, :method_there
|
||||
# end
|
||||
#
|
||||
# _other_method_name_ defaults to method_name, if it wasn't given.
|
||||
#def delegate(method_name, to: UNSET, as: method_name)
|
||||
def delegate(method_name, opts = {})
|
||||
to = opts[:to] || UNSET
|
||||
as = opts[:as] || method_name
|
||||
raise ArgumentError, "to argument wasn't defined" if to == UNSET
|
||||
to = to.to_s
|
||||
case
|
||||
when to[0, 2] == '@@'
|
||||
define_method(as) do |*args, &block|
|
||||
if self.class.class_variable_defined?(to)
|
||||
self.class.class_variable_get(to).__send__(method_name, *args, &block)
|
||||
end
|
||||
end
|
||||
when to[0] == ?@
|
||||
define_method(as) do |*args, &block|
|
||||
if instance_variable_defined?(to)
|
||||
instance_variable_get(to).__send__(method_name, *args, &block)
|
||||
end
|
||||
end
|
||||
when (?A..?Z).include?(to[0])
|
||||
define_method(as) do |*args, &block|
|
||||
Tins::DeepConstGet.deep_const_get(to).__send__(method_name, *args, &block)
|
||||
end
|
||||
else
|
||||
define_method(as) do |*args, &block|
|
||||
__send__(to).__send__(method_name, *args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This module includes the block_self module_function.
|
||||
module BlockSelf
|
||||
module_function
|
||||
|
||||
# This method returns the receiver _self_ of the context in which _block_
|
||||
# was created.
|
||||
def block_self(&block)
|
||||
eval 'self', block.__send__(:binding)
|
||||
end
|
||||
end
|
||||
|
||||
# This module contains a configurable method missing delegator and can be
|
||||
# mixed into a module/class.
|
||||
module MethodMissingDelegator
|
||||
|
||||
# Including this module in your classes makes an _initialize_ method
|
||||
# available, whose first argument is used as method_missing_delegator
|
||||
# attribute. If a superior _initialize_ method was defined it is called
|
||||
# with all arguments but the first.
|
||||
module DelegatorModule
|
||||
include Tins::MethodMissingDelegator
|
||||
|
||||
def initialize(delegator, *a, &b)
|
||||
self.method_missing_delegator = delegator
|
||||
super(*a, &b) if defined? super
|
||||
end
|
||||
end
|
||||
|
||||
# This class includes DelegatorModule and can be used as a superclass
|
||||
# instead of including DelegatorModule.
|
||||
class DelegatorClass
|
||||
include DelegatorModule
|
||||
end
|
||||
|
||||
# This object will be the receiver of all missing method calls, if it has a
|
||||
# value other than nil.
|
||||
attr_accessor :method_missing_delegator
|
||||
|
||||
# Delegates all missing method calls to _method_missing_delegator_ if this
|
||||
# attribute has been set. Otherwise it will call super.
|
||||
def method_missing(id, *a, &b)
|
||||
unless method_missing_delegator.nil?
|
||||
method_missing_delegator.__send__(id, *a, &b)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ParameterizedModule
|
||||
# Pass _args_ and _block_ to configure the module and then return it after
|
||||
# calling the parameterize method has been called with these arguments. The
|
||||
# _parameterize_ method should return a configured module.
|
||||
def parameterize_for(*args, &block)
|
||||
respond_to?(:parameterize) ? parameterize(*args, &block) : self
|
||||
end
|
||||
end
|
||||
|
||||
module FromModule
|
||||
include ParameterizedModule
|
||||
|
||||
alias from parameterize_for
|
||||
|
||||
def parameterize(opts = {})
|
||||
modul = opts[:module] or raise ArgumentError, 'option :module is required'
|
||||
import_methods = Array(opts[:methods])
|
||||
result = modul.dup
|
||||
remove_methods = modul.instance_methods.map(&:to_sym) - import_methods.map(&:to_sym)
|
||||
remove_methods.each do |m|
|
||||
begin
|
||||
result.__send__ :remove_method, m
|
||||
rescue NameError
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
module Scope
|
||||
def scope_push(scope_frame, name = :default)
|
||||
scope_get(name).push scope_frame
|
||||
self
|
||||
end
|
||||
|
||||
def scope_pop(name = :default)
|
||||
scope_get(name).pop
|
||||
scope_get(name).empty? and Thread.current[name] = nil
|
||||
self
|
||||
end
|
||||
|
||||
def scope_top(name = :default)
|
||||
scope_get(name).last
|
||||
end
|
||||
|
||||
def scope_reverse(name = :default, &block)
|
||||
scope_get(name).reverse_each(&block)
|
||||
end
|
||||
|
||||
def scope_block(scope_frame, name = :default)
|
||||
scope_push(scope_frame, name)
|
||||
yield
|
||||
ensure
|
||||
scope_pop(name)
|
||||
end
|
||||
|
||||
def scope_get(name = :default)
|
||||
Thread.current[name] ||= []
|
||||
end
|
||||
|
||||
def scope(name = :default)
|
||||
scope_get(name).dup
|
||||
end
|
||||
end
|
||||
|
||||
module DynamicScope
|
||||
class Context < Hash
|
||||
def [](name)
|
||||
super name.to_sym
|
||||
end
|
||||
|
||||
def []=(name, value)
|
||||
super name.to_sym, value
|
||||
end
|
||||
end
|
||||
|
||||
include Scope
|
||||
|
||||
attr_accessor :dynamic_scope_name
|
||||
|
||||
def dynamic_defined?(id)
|
||||
self.dynamic_scope_name ||= :variables
|
||||
scope_reverse(dynamic_scope_name) { |c| c.key?(id) and return true }
|
||||
false
|
||||
end
|
||||
|
||||
def dynamic_scope(&block)
|
||||
self.dynamic_scope_name ||= :variables
|
||||
scope_block(Context.new, dynamic_scope_name, &block)
|
||||
end
|
||||
|
||||
def method_missing(id, *args)
|
||||
self.dynamic_scope_name ||= :variables
|
||||
if args.empty? and scope_reverse(dynamic_scope_name) { |c| c.key?(id) and return c[id] }
|
||||
super
|
||||
elsif args.size == 1 and id.to_s =~ /(.*?)=\Z/
|
||||
c = scope_top(dynamic_scope_name) or super
|
||||
c[$1] = args.first
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
DSLKit = Tins
|
@ -1,95 +0,0 @@
|
||||
module Tins
|
||||
class Duration
|
||||
include Comparable
|
||||
|
||||
def initialize(seconds)
|
||||
@negative = seconds < 0
|
||||
seconds = seconds.abs
|
||||
@original_seconds = seconds
|
||||
@days, @hours, @minutes, @seconds, @fractional_seconds =
|
||||
[ 86_400, 3600, 60, 1, 0 ].inject([ [], seconds ]) {|(r, s), d|
|
||||
if d > 0
|
||||
dd, rest = s.divmod(d)
|
||||
r << dd
|
||||
[ r, rest ]
|
||||
else
|
||||
r << s
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def to_f
|
||||
@original_seconds.to_f
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
to_f <=> other.to_f
|
||||
end
|
||||
|
||||
def negative?
|
||||
@negative
|
||||
end
|
||||
|
||||
def days?
|
||||
@days > 0
|
||||
end
|
||||
|
||||
def hours?
|
||||
@hours > 0
|
||||
end
|
||||
|
||||
def minutes?
|
||||
@minutes > 0
|
||||
end
|
||||
|
||||
def seconds?
|
||||
@seconds > 0
|
||||
end
|
||||
|
||||
def fractional_seconds?
|
||||
@fractional_seconds > 0
|
||||
end
|
||||
|
||||
def format(template = '%S%d+%h:%m:%s.%f', precision: nil)
|
||||
result = template.gsub(/%[DdhmSs]/) { |directive|
|
||||
case directive
|
||||
when '%S' then ?- if negative?
|
||||
when '%d' then @days
|
||||
when '%h' then '%02u' % @hours
|
||||
when '%m' then '%02u' % @minutes
|
||||
when '%s' then '%02u' % @seconds
|
||||
when '%D' then format_smart
|
||||
end
|
||||
}
|
||||
if result.include?('%f')
|
||||
if precision
|
||||
fractional_seconds = "%.#{precision}f" % @fractional_seconds
|
||||
else
|
||||
fractional_seconds = '%f' % @fractional_seconds
|
||||
end
|
||||
result.gsub!('%f', fractional_seconds[2..-1])
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def to_s
|
||||
format_smart
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_smart
|
||||
template = '%h:%m:%s'
|
||||
precision = nil
|
||||
if days?
|
||||
template.prepend '%d+'
|
||||
end
|
||||
if fractional_seconds?
|
||||
template << '.%f'
|
||||
precision = 3
|
||||
end
|
||||
template.prepend '%S'
|
||||
format template, precision: precision
|
||||
end
|
||||
end
|
||||
end
|
@ -1,27 +0,0 @@
|
||||
module Tins
|
||||
module Expose
|
||||
# Expose any (private/protected) method or internal state of this object
|
||||
# returning the result for specing purposes.
|
||||
#
|
||||
# @param method_name [ Symbol | String ] name of the method
|
||||
# (shortcut for reader methods).
|
||||
# @param block [ Proc ] any private/protected methods of the object can be
|
||||
# called in this block.
|
||||
#
|
||||
# @return [ Object ] result of the method or block call
|
||||
def expose(method_name = nil, *args, &block)
|
||||
if block
|
||||
instance_eval(&block)
|
||||
elsif method_name.nil?
|
||||
methods = private_methods(true) + protected_methods(true)
|
||||
o = dup
|
||||
o.singleton_class.class_eval do
|
||||
public(*methods)
|
||||
end
|
||||
o
|
||||
elsif method_name
|
||||
__send__(method_name, *args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,14 +0,0 @@
|
||||
module Tins
|
||||
module ExtractLastArgumentOptions
|
||||
def extract_last_argument_options
|
||||
last_argument = last
|
||||
if last_argument.respond_to?(:to_hash) and
|
||||
options = last_argument.to_hash.dup
|
||||
then
|
||||
return self[0..-2], options
|
||||
else
|
||||
return dup, {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,83 +0,0 @@
|
||||
module Tins
|
||||
module FileBinary
|
||||
module Constants
|
||||
SEEK_SET = ::File::SEEK_SET
|
||||
|
||||
ZERO = "\x00"
|
||||
BINARY = "\x01-\x1f\x7f-\xff"
|
||||
|
||||
if defined?(::Encoding)
|
||||
ZERO.force_encoding(Encoding::ASCII_8BIT)
|
||||
BINARY.force_encoding(Encoding::ASCII_8BIT)
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
# Default options can be queried/set via this hash.
|
||||
attr_accessor :default_options
|
||||
end
|
||||
self.default_options = {
|
||||
offset: 0,
|
||||
buffer_size: 2 ** 13,
|
||||
percentage_binary: 30.0,
|
||||
percentage_zeros: 0.0,
|
||||
}
|
||||
|
||||
# Returns true if this file is considered to be binary, false if it is not
|
||||
# considered to be binary, and nil if it was empty.
|
||||
#
|
||||
# A file is considered to be binary if the percentage of zeros exceeds
|
||||
# <tt>options[:percentage_zeros]</tt> or the percentage of binary bytes
|
||||
# (8-th bit is 1) exceeds <tt>options[:percentage_binary]</tt> in the
|
||||
# buffer of size <tt>options[:buffer_size]</tt> that is checked (beginning
|
||||
# from offset <tt>options[:offset]</tt>). If an option isn't given the one
|
||||
# from FileBinary.default_options is used instead.
|
||||
def binary?(options = {})
|
||||
options = FileBinary.default_options.merge(options)
|
||||
old_pos = tell
|
||||
seek options[:offset], Constants::SEEK_SET
|
||||
data = read options[:buffer_size]
|
||||
!data or data.empty? and return nil
|
||||
data_size = data.size
|
||||
data.count(Constants::ZERO).to_f / data_size >
|
||||
options[:percentage_zeros] / 100.0 and return true
|
||||
data.count(Constants::BINARY).to_f / data_size >
|
||||
options[:percentage_binary] / 100.0
|
||||
ensure
|
||||
old_pos and seek old_pos, Constants::SEEK_SET
|
||||
end
|
||||
|
||||
# Returns true if FileBinary#binary? returns false, false if
|
||||
# FileBinary#binary? returns true, and nil otherwise. For an explanation of
|
||||
# +options+, see FileBinary#binary?.
|
||||
def ascii?(options = {})
|
||||
case binary?(options)
|
||||
when true then false
|
||||
when false then true
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(modul)
|
||||
modul.instance_eval do
|
||||
extend ClassMethods
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Returns true if the file with name +name+ is considered to be binary
|
||||
# using the FileBinary#binary? method.
|
||||
def binary?(name, options = {})
|
||||
open(name, 'rb') { |f| f.binary?(options) }
|
||||
end
|
||||
|
||||
# Returns true if the file with name +name+ is considered to be ascii
|
||||
# using the FileBinary#ascii? method.
|
||||
def ascii?(name, options = {})
|
||||
open(name, 'rb') { |f| f.ascii?(options) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,149 +0,0 @@
|
||||
require 'enumerator'
|
||||
require 'pathname'
|
||||
require 'tins/module_group'
|
||||
|
||||
module Tins
|
||||
module Find
|
||||
EXPECTED_STANDARD_ERRORS = ModuleGroup[
|
||||
Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP,
|
||||
Errno::ENAMETOOLONG
|
||||
]
|
||||
|
||||
class Finder
|
||||
module PathExtension
|
||||
attr_accessor :finder
|
||||
|
||||
def finder_stat
|
||||
finder.protect_from_errors do
|
||||
finder.follow_symlinks ? File.stat(self) : File.lstat(self)
|
||||
end
|
||||
end
|
||||
|
||||
def file
|
||||
finder.protect_from_errors do
|
||||
File.new(self) if file?
|
||||
end
|
||||
end
|
||||
|
||||
def file?
|
||||
finder.protect_from_errors { s = finder_stat and s.file? }
|
||||
end
|
||||
|
||||
def directory?
|
||||
finder.protect_from_errors { s = finder_stat and s.directory? }
|
||||
end
|
||||
|
||||
def exist?
|
||||
finder.protect_from_errors { File.exist?(self) }
|
||||
end
|
||||
|
||||
def stat
|
||||
finder.protect_from_errors { File.stat(self) }
|
||||
end
|
||||
|
||||
def lstat
|
||||
finder.protect_from_errors { File.lstat(self) }
|
||||
end
|
||||
|
||||
def pathname
|
||||
Pathname.new(self)
|
||||
end
|
||||
|
||||
def suffix
|
||||
pathname.extname[1..-1] || ''
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(opts = {})
|
||||
@show_hidden = opts.fetch(:show_hidden) { true }
|
||||
@raise_errors = opts.fetch(:raise_errors) { false }
|
||||
@follow_symlinks = opts.fetch(:follow_symlinks) { true }
|
||||
if opts.key?(:visit) && opts.key?(:suffix)
|
||||
raise ArgumentError, 'either use visit or suffix argument'
|
||||
elsif opts.key?(:visit)
|
||||
@visit = opts.fetch(:visit) { -> path { true } }
|
||||
elsif opts.key?(:suffix)
|
||||
@suffix = Array(opts[:suffix])
|
||||
@visit = -> path { @suffix.nil? || @suffix.empty? || @suffix.include?(path.suffix) }
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :show_hidden
|
||||
|
||||
attr_accessor :raise_errors
|
||||
|
||||
attr_accessor :follow_symlinks
|
||||
|
||||
attr_accessor :suffix
|
||||
|
||||
def visit_path?(path)
|
||||
if !defined?(@visit) || @visit.nil?
|
||||
true
|
||||
else
|
||||
@visit.(path)
|
||||
end
|
||||
end
|
||||
|
||||
def find(*paths)
|
||||
block_given? or return enum_for(__method__, *paths)
|
||||
paths.collect! { |d| d.dup }
|
||||
while path = paths.shift
|
||||
path = prepare_path(path)
|
||||
catch(:prune) do
|
||||
stat = path.finder_stat or next
|
||||
visit_path?(path) and yield path
|
||||
if stat.directory?
|
||||
ps = protect_from_errors { Dir.entries(path) } or next
|
||||
ps.sort!
|
||||
ps.reverse_each do |p|
|
||||
next if p == "." or p == ".."
|
||||
next if !@show_hidden && p.start_with?('.')
|
||||
p = File.join(path, p)
|
||||
paths.unshift p
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def prepare_path(path)
|
||||
path = path.dup
|
||||
path.extend PathExtension
|
||||
path.finder = self
|
||||
path
|
||||
end
|
||||
|
||||
def protect_from_errors(errors = Find::EXPECTED_STANDARD_ERRORS)
|
||||
yield
|
||||
rescue errors
|
||||
raise_errors and raise
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Calls the associated block with the name of every path and directory
|
||||
# listed as arguments, then recursively on their subdirectories, and so on.
|
||||
#
|
||||
# See the +Find+ module documentation for an example.
|
||||
#
|
||||
def find(*paths, &block) # :yield: path
|
||||
opts = Hash === paths.last ? paths.pop : {}
|
||||
Finder.new(opts).find(*paths, &block)
|
||||
end
|
||||
|
||||
#
|
||||
# Skips the current path or directory, restarting the loop with the next
|
||||
# entry. If the current path is a directory, that directory will not be
|
||||
# recursively entered. Meaningful only within the block associated with
|
||||
# Find::find.
|
||||
#
|
||||
# See the +Find+ module documentation for an example.
|
||||
#
|
||||
def prune
|
||||
throw :prune
|
||||
end
|
||||
|
||||
module_function :find, :prune
|
||||
end
|
||||
end
|
@ -1,68 +0,0 @@
|
||||
module Tins
|
||||
# This class can create generator objects, that can produce all tuples, that
|
||||
# would be created by as many for-loops as dimensions were given.
|
||||
#
|
||||
# The generator
|
||||
# g = Tins::Generator[1..2, %w[a b c]]
|
||||
# produces
|
||||
# g.to_a # => [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"]]
|
||||
#
|
||||
# The 'each' method can be used to iterate over the tuples
|
||||
# g.each { |a, b| puts "#{a} #{b}" }
|
||||
# and Tins::Generator includes the Enumerable module, so
|
||||
# Enumerable.instance_methods can be used as well:
|
||||
# g.select { |a, b| %w[a c].include? b } # => [[1, "a"], [1, "c"], [2, "a"], [2, "c"]]
|
||||
#
|
||||
class Generator
|
||||
include Enumerable
|
||||
|
||||
# Create a new Generator object from the enumberables _enums_.
|
||||
def self.[](*enums)
|
||||
new(enums)
|
||||
end
|
||||
|
||||
# Create a new Generator instance. Use the objects in the Array _enums_
|
||||
# as dimensions. The should all respond to the :each method (see module
|
||||
# Enumerable in the core ruby library).
|
||||
def initialize(enums)
|
||||
@enums, @iterators, @n = [], [], 0
|
||||
enums.each { |e| add_dimension(e) }
|
||||
end
|
||||
|
||||
# Iterate over all tuples produced by this generator and yield to them.
|
||||
def each(&block) # :yield: tuple
|
||||
recurse(&block)
|
||||
self
|
||||
end
|
||||
|
||||
def recurse(tuple = [ nil ] * @n, i = 0, &block)
|
||||
if i < @n - 1 then
|
||||
@enums[i].__send__(@iterators[i]) do |x|
|
||||
tuple[i] = x
|
||||
recurse(tuple, i + 1, &block)
|
||||
end
|
||||
else
|
||||
@enums[i].__send__(@iterators[i]) do |x|
|
||||
tuple[i] = x
|
||||
yield tuple.dup
|
||||
end
|
||||
end
|
||||
end
|
||||
private :recurse
|
||||
|
||||
# Add another dimension to this generator. _enum_ is an object, that ought
|
||||
# to respond to the _iterator_ method (defaults to :each).
|
||||
def add_dimension(enum, iterator = :each)
|
||||
@enums << enum
|
||||
@iterators << iterator
|
||||
@n += 1
|
||||
end
|
||||
|
||||
# Return the size of this generator, that is the number of its dimensions.
|
||||
def size
|
||||
@enums.size
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,96 +0,0 @@
|
||||
module Tins
|
||||
module GO
|
||||
module EnumerableExtension
|
||||
def push(argument)
|
||||
@arguments ||= []
|
||||
@arguments.push argument
|
||||
self
|
||||
end
|
||||
alias << push
|
||||
|
||||
def each(&block)
|
||||
@arguments.each(&block)
|
||||
self
|
||||
end
|
||||
include Enumerable
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
# Parses the argument array _args_, according to the pattern _s_, to
|
||||
# retrieve the single character command line options from it. If _s_ is
|
||||
# 'xy:' an option '-x' without an option argument is searched, and an
|
||||
# option '-y foo' with an option argument ('foo'). To disable the '-x'
|
||||
# option, pass '~x'.
|
||||
#
|
||||
# The _defaults_ argument specifies default values for the options.
|
||||
#
|
||||
# An option hash is returned with all found options set to true or the
|
||||
# found option argument.
|
||||
def go(s, args = ARGV, defaults: {})
|
||||
d = defaults || {}
|
||||
b, v = s.scan(/(.)(:?)/).inject([ {}, {} ]) { |t, (o, a)|
|
||||
a = a == ?:
|
||||
t[a ? 1 : 0][o] = a ? nil : false
|
||||
t
|
||||
}
|
||||
b.each_key do |k|
|
||||
d.key?(k) or next
|
||||
if [ 0, false, nil ].include?(d[k])
|
||||
b[k] = false
|
||||
elsif d[k].respond_to?(:to_int)
|
||||
b[k] = d[k].to_int
|
||||
else
|
||||
b[k] = 1
|
||||
end
|
||||
end
|
||||
v.each_key do |k|
|
||||
d.key?(k) or next
|
||||
if [ 0, false, nil ].include?(d[k])
|
||||
v[k] = nil
|
||||
else
|
||||
v[k] = d[k].to_s
|
||||
end
|
||||
end
|
||||
r = []
|
||||
while a = args.shift
|
||||
/\A-(?<p>.+)/ =~ a or (r << a; next)
|
||||
until p == ''
|
||||
o = p.slice!(0, 1)
|
||||
if v.key?(o)
|
||||
if p.empty? && args.empty?
|
||||
r << a
|
||||
break 1
|
||||
elsif p == ''
|
||||
a = args.shift
|
||||
else
|
||||
a = p
|
||||
end
|
||||
if v[o].nil? || !(EnumerableExtension === v[o])
|
||||
a = a.dup
|
||||
a.extend EnumerableExtension
|
||||
a << a
|
||||
v[o] = a
|
||||
else
|
||||
v[o] << a
|
||||
end
|
||||
break
|
||||
elsif b.key?(o)
|
||||
if b[o]
|
||||
b[o] += 1
|
||||
else
|
||||
b[o] = 1
|
||||
end
|
||||
else
|
||||
r << a
|
||||
end
|
||||
end && break
|
||||
end
|
||||
r.reject! { |a| (b[p] = false) || true if /\A~(?<p>.)/ =~ a }
|
||||
args.replace r
|
||||
b.merge(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,48 +0,0 @@
|
||||
require 'tins/thread_local'
|
||||
|
||||
module Tins
|
||||
module HashSymbolizeKeysRecursive
|
||||
extend Tins::ThreadLocal
|
||||
|
||||
thread_local :seen
|
||||
|
||||
def symbolize_keys_recursive(circular: nil)
|
||||
self.seen = {}
|
||||
_symbolize_keys_recursive(self, circular: circular)
|
||||
ensure
|
||||
self.seen = nil
|
||||
end
|
||||
|
||||
def symbolize_keys_recursive!(circular: nil)
|
||||
replace symbolize_keys_recursive(circular: circular)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _symbolize_keys_recursive(object, circular: nil)
|
||||
case
|
||||
when seen[object.__id__]
|
||||
object = circular
|
||||
when Hash === object
|
||||
seen[object.__id__] = true
|
||||
new_object = object.class.new
|
||||
seen[new_object.__id__] = true
|
||||
object.each do |k, v|
|
||||
new_object[k.to_s.to_sym] = _symbolize_keys_recursive(v, circular: circular)
|
||||
end
|
||||
object = new_object
|
||||
when Array === object
|
||||
seen[object.__id__] = true
|
||||
new_object = object.class.new(object.size)
|
||||
seen[new_object.__id__] = true
|
||||
object.each_with_index do |v, i|
|
||||
new_object[i] = _symbolize_keys_recursive(v, circular: circular)
|
||||
end
|
||||
object = new_object
|
||||
end
|
||||
object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,15 +0,0 @@
|
||||
module Tins
|
||||
module HashUnion
|
||||
def |(other)
|
||||
case
|
||||
when other.respond_to?(:to_hash)
|
||||
other = other.to_hash
|
||||
when other.respond_to?(:to_h)
|
||||
other = other.to_h
|
||||
end
|
||||
other.merge(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,7 +0,0 @@
|
||||
module Tins
|
||||
module IfPredicate
|
||||
def if?
|
||||
self ? self : nil
|
||||
end
|
||||
end
|
||||
end
|
@ -1,40 +0,0 @@
|
||||
module Tins
|
||||
module Implement
|
||||
MESSAGES = {
|
||||
default: 'method %{method_name} not implemented in module %{module}',
|
||||
subclass: 'method %{method_name} has to be implemented in '\
|
||||
'subclasses of %{module}',
|
||||
submodule: 'method %{method_name} has to be implemented in '\
|
||||
'submodules of %{module}',
|
||||
}
|
||||
|
||||
def implement(method_name, msg = :default)
|
||||
method_name.nil? and return
|
||||
case msg
|
||||
when ::Symbol
|
||||
msg = MESSAGES.fetch(msg)
|
||||
when ::Hash
|
||||
return implement method_name, msg.fetch(:in)
|
||||
end
|
||||
display_method_name = method_name
|
||||
if m = instance_method(method_name) rescue nil
|
||||
m.extend Tins::MethodDescription
|
||||
display_method_name = m.description(style: :name)
|
||||
end
|
||||
begin
|
||||
msg = msg % { method_name: display_method_name, module: self }
|
||||
rescue KeyError
|
||||
end
|
||||
define_method(method_name) do |*|
|
||||
raise ::NotImplementedError, msg
|
||||
end
|
||||
end
|
||||
|
||||
def implement_in_submodule(method_name)
|
||||
implement method_name,
|
||||
'method %{method_name} has to be implemented in submodules of'\
|
||||
' %{module}'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,44 +0,0 @@
|
||||
require 'thread'
|
||||
|
||||
module Tins
|
||||
class Limited
|
||||
# Create a Limited instance, that runs _maximum_ threads at most.
|
||||
def initialize(maximum)
|
||||
@mutex = Mutex.new
|
||||
@continue = ConditionVariable.new
|
||||
@maximum = Integer(maximum)
|
||||
raise ArgumentError, "maximum < 1" if @maximum < 1
|
||||
@count = 0
|
||||
@tg = ThreadGroup.new
|
||||
end
|
||||
|
||||
# The maximum number of worker threads.
|
||||
attr_reader :maximum
|
||||
|
||||
# Execute _maximum_ number of threads in parallel.
|
||||
def execute
|
||||
@mutex.synchronize do
|
||||
loop do
|
||||
if @count < @maximum
|
||||
@count += 1
|
||||
Thread.new do
|
||||
@tg.add Thread.current
|
||||
yield
|
||||
@mutex.synchronize { @count -= 1 }
|
||||
@continue.signal
|
||||
end
|
||||
return
|
||||
else
|
||||
@continue.wait(@mutex)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def wait
|
||||
@tg.list.each(&:join)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,123 +0,0 @@
|
||||
module Tins
|
||||
class LinesFile
|
||||
module LineExtension
|
||||
attr_reader :line_number
|
||||
|
||||
def filename
|
||||
lines_file.filename.dup
|
||||
end
|
||||
end
|
||||
|
||||
def self.for_filename(filename, line_number = nil)
|
||||
obj = new(File.readlines(filename), line_number)
|
||||
obj.filename = filename
|
||||
obj
|
||||
end
|
||||
|
||||
def self.for_file(file, line_number = nil)
|
||||
obj = new(file.readlines, line_number)
|
||||
obj.filename = file.path
|
||||
obj
|
||||
end
|
||||
|
||||
def self.for_lines(lines, line_number = nil)
|
||||
new(lines, line_number)
|
||||
end
|
||||
|
||||
def initialize(lines, line_number = nil)
|
||||
@lines = lines
|
||||
@lines.each_with_index do |line, i|
|
||||
line.extend LineExtension
|
||||
line.instance_variable_set :@line_number, i + 1
|
||||
line.instance_variable_set :@lines_file, self
|
||||
end
|
||||
instance_variable_set :@line_number, line_number || (@lines.empty? ? 0 : 1)
|
||||
end
|
||||
|
||||
attr_accessor :filename
|
||||
|
||||
attr_reader :line_number
|
||||
|
||||
def rewind
|
||||
self.line_number = 1
|
||||
self
|
||||
end
|
||||
|
||||
def next!
|
||||
old = line_number
|
||||
self.line_number += 1
|
||||
line_number > old ? self : nil
|
||||
end
|
||||
|
||||
def previous!
|
||||
old = line_number
|
||||
self.line_number -= 1
|
||||
line_number < old ? self : nil
|
||||
end
|
||||
|
||||
def line_number=(number)
|
||||
number = number.to_i
|
||||
if number > 0 && number <= last_line_number
|
||||
@line_number = number
|
||||
end
|
||||
end
|
||||
|
||||
def last_line_number
|
||||
@lines.size
|
||||
end
|
||||
|
||||
def empty?
|
||||
@lines.empty?
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
empty? and return self
|
||||
old_line_number = line_number
|
||||
1.upto(last_line_number) do |number|
|
||||
self.line_number = number
|
||||
block.call(line)
|
||||
end
|
||||
self
|
||||
ensure
|
||||
self.line_number = old_line_number
|
||||
end
|
||||
include Enumerable
|
||||
|
||||
def line
|
||||
index = line_number - 1
|
||||
@lines[index] if index >= 0
|
||||
end
|
||||
|
||||
def file_linenumber
|
||||
"#{filename}:#{line_number}"
|
||||
end
|
||||
|
||||
def match_backward(regexp, previous_after_match = false)
|
||||
begin
|
||||
if line =~ regexp
|
||||
previous_after_match and previous!
|
||||
return $~.captures
|
||||
end
|
||||
end while previous!
|
||||
end
|
||||
|
||||
def match_forward(regexp, next_after_match = false)
|
||||
begin
|
||||
if line =~ regexp
|
||||
next_after_match and next!
|
||||
return $~.captures
|
||||
end
|
||||
end while next!
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{line_number} #{line.chomp}"
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class}: #{to_s.inspect}>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,91 +0,0 @@
|
||||
require 'tins/extract_last_argument_options'
|
||||
|
||||
module Tins
|
||||
module Memoize
|
||||
module CacheMethods
|
||||
# Return the cache object.
|
||||
def __memoize_cache__
|
||||
@__memoize_cache__ ||= {}
|
||||
end
|
||||
|
||||
# Clear cached values for all methods/functions.
|
||||
def memoize_cache_clear
|
||||
__memoize_cache__.clear
|
||||
self
|
||||
end
|
||||
|
||||
def memoize_apply_visibility(id)
|
||||
visibility = instance_eval do
|
||||
case
|
||||
when private_method_defined?(id)
|
||||
:private
|
||||
when protected_method_defined?(id)
|
||||
:protected
|
||||
end
|
||||
end
|
||||
yield
|
||||
ensure
|
||||
visibility and __send__(visibility, id)
|
||||
end
|
||||
end
|
||||
|
||||
class ::Module
|
||||
# Automatically memoize calls of the the methods +method_ids+. The
|
||||
# memoized results do NOT ONLY depend on the arguments, but ALSO on the
|
||||
# object the method is called on.
|
||||
def memoize_method(*method_ids)
|
||||
method_ids.extend(ExtractLastArgumentOptions)
|
||||
method_ids, opts = method_ids.extract_last_argument_options
|
||||
include CacheMethods
|
||||
method_ids.each do |method_id|
|
||||
method_id = method_id.to_s.to_sym
|
||||
memoize_apply_visibility method_id do
|
||||
orig_method = instance_method(method_id)
|
||||
__send__(:define_method, method_id) do |*args|
|
||||
mc = __memoize_cache__
|
||||
if mc.key?(method_id) and result = mc[method_id][args]
|
||||
result
|
||||
else
|
||||
(mc[method_id] ||= {})[args] = result = orig_method.bind(self).call(*args)
|
||||
$DEBUG and warn "#{self.class} cached method #{method_id}(#{args.inspect unless args.empty?}) = #{result.inspect} [#{__id__}]"
|
||||
opts[:freeze] and result.freeze
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
method_ids.size == 1 ? method_ids.first : method_ids
|
||||
end
|
||||
|
||||
include CacheMethods
|
||||
|
||||
# Automatically memoize calls of the functions +function_ids+. The
|
||||
# memoized result does ONLY depend on the arguments given to the
|
||||
# function.
|
||||
def memoize_function(*function_ids)
|
||||
function_ids.extend(ExtractLastArgumentOptions)
|
||||
function_ids, opts = function_ids.extract_last_argument_options
|
||||
mc = __memoize_cache__
|
||||
function_ids.each do |function_id|
|
||||
function_id = function_id.to_s.to_sym
|
||||
memoize_apply_visibility function_id do
|
||||
orig_function = instance_method(function_id)
|
||||
__send__(:define_method, function_id) do |*args|
|
||||
if mc.key?(function_id) and result = mc[function_id][args]
|
||||
result
|
||||
else
|
||||
(mc[function_id] ||= {})[args] = result = orig_function.bind(self).call(*args)
|
||||
opts[:freeze] and result.freeze
|
||||
$DEBUG and warn "#{self.class} cached function #{function_id}(#{args.inspect unless args.empty?}) = #{result.inspect}"
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
function_ids.size == 1 ? function_ids.first : function_ids
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,143 +0,0 @@
|
||||
module Tins
|
||||
module MethodDescription
|
||||
class Parameters
|
||||
class Parameter < Struct.new(:type, :name)
|
||||
def ==(other)
|
||||
type == other.type
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class} #{to_s.inspect}>"
|
||||
end
|
||||
end
|
||||
|
||||
class RestParameter < Parameter
|
||||
def to_s
|
||||
"*#{name}"
|
||||
end
|
||||
end
|
||||
|
||||
class KeyrestParameter < Parameter
|
||||
def to_s
|
||||
"**#{name}"
|
||||
end
|
||||
end
|
||||
|
||||
class ReqParameter < Parameter
|
||||
def to_s
|
||||
name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
class OptParameter < Parameter
|
||||
def to_s
|
||||
"#{name}=?"
|
||||
end
|
||||
end
|
||||
|
||||
class KeyParameter < Parameter
|
||||
def to_s
|
||||
"#{name}:?"
|
||||
end
|
||||
end
|
||||
|
||||
class KeyreqParameter < Parameter
|
||||
def to_s
|
||||
"#{name}:"
|
||||
end
|
||||
end
|
||||
|
||||
class BlockParameter < Parameter
|
||||
def to_s
|
||||
"&#{name}"
|
||||
end
|
||||
end
|
||||
|
||||
class GenericParameter < Parameter
|
||||
def to_s
|
||||
[ name, type ] * ?:
|
||||
end
|
||||
end
|
||||
|
||||
def self.build(type, name)
|
||||
parameter_classname = "#{type.to_s.capitalize}Parameter"
|
||||
parameter_class =
|
||||
if const_defined? parameter_classname
|
||||
const_get parameter_classname
|
||||
else
|
||||
GenericParameter
|
||||
end
|
||||
parameter_class.new(type, name)
|
||||
end
|
||||
end
|
||||
|
||||
class Signature
|
||||
def initialize(*parameters)
|
||||
@parameters = parameters
|
||||
end
|
||||
|
||||
attr_reader :parameters
|
||||
|
||||
def eql?(other)
|
||||
@parameters.eql? other.parameters
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
@parameters == other.parameters
|
||||
end
|
||||
|
||||
def ===(method)
|
||||
self == method.signature
|
||||
end
|
||||
|
||||
def to_s
|
||||
@parameters * ?,
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class} (#{to_s})>"
|
||||
end
|
||||
end
|
||||
|
||||
def signature
|
||||
description style: :parameters
|
||||
end
|
||||
|
||||
def description(style: :namespace)
|
||||
valid_styles = %i[ namespace name parameters ]
|
||||
valid_styles.include?(style) or
|
||||
raise ArgumentError,
|
||||
"style has to be one of #{valid_styles * ', '}"
|
||||
if respond_to?(:parameters)
|
||||
generated_name = 'x0'
|
||||
parameter_array = parameters.map { |p_type, p_name|
|
||||
unless p_name
|
||||
generated_name = generated_name.succ
|
||||
p_name = generated_name
|
||||
end
|
||||
Parameters.build(p_type, p_name)
|
||||
}
|
||||
signature = Signature.new(*parameter_array)
|
||||
if style == :parameters
|
||||
return signature
|
||||
end
|
||||
end
|
||||
result = ''
|
||||
if style == :namespace
|
||||
if owner <= Module
|
||||
result << receiver.to_s << ?. # XXX Better to use owner here as well?
|
||||
else
|
||||
result << owner.name.to_s << ?#
|
||||
end
|
||||
end
|
||||
if %i[ namespace name ].include?(style)
|
||||
result << name.to_s << '('
|
||||
end
|
||||
result << (signature || arity).to_s
|
||||
if %i[ namespace name ].include?(style)
|
||||
result << ?)
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
@ -1,55 +0,0 @@
|
||||
module Tins
|
||||
# This module can be mixed into all classes, whose instances respond to the
|
||||
# [] and size-methods, like for example Array. The returned elements from []
|
||||
# should respond to the succ method.
|
||||
module Minimize
|
||||
# Returns a minimized version of this object, that is successive elements
|
||||
# are substituted with ranges a..b. In the situation ..., x, y,... and y !=
|
||||
# x.succ a range x..x is created, to make it easier to iterate over all the
|
||||
# ranges in one run. A small example:
|
||||
# [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ].minimize # => [ 'A'..'C', 'G'..'G', 'K'..'M' ]
|
||||
#
|
||||
# If the order of the original elements doesn't matter, it's a good idea to
|
||||
# first sort them and then minimize:
|
||||
# [ 5, 1, 4, 2 ].sort.minimize # => [ 1..2, 4..5 ]
|
||||
def minimize
|
||||
result = []
|
||||
last_index = size - 1
|
||||
size.times do |i|
|
||||
result << [ self[0] ] if i == 0
|
||||
if self[i].succ != self[i + 1] or i == last_index
|
||||
result[-1] << self[i]
|
||||
result << [ self[i + 1] ] unless i == last_index
|
||||
end
|
||||
end
|
||||
result.map! { |a, b| a..b }
|
||||
end
|
||||
|
||||
# First minimizes this object, then calls the replace method with the
|
||||
# result.
|
||||
def minimize!
|
||||
replace minimize
|
||||
end
|
||||
|
||||
# Invert a minimized version of an object. Some small examples:
|
||||
# [ 'A'..'C', 'G'..'G', 'K'..'M' ].unminimize # => [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ]
|
||||
# and
|
||||
# [ 1..2, 4..5 ].unminimize # => [ 1, 2, 4, 5 ]
|
||||
def unminimize
|
||||
result = []
|
||||
for range in self
|
||||
for e in range
|
||||
result << e
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
# Invert a minimized version of this object in place.
|
||||
def unminimize!
|
||||
replace unminimize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,13 +0,0 @@
|
||||
module Tins
|
||||
module ModuleGroup
|
||||
def self.[](*modules)
|
||||
modul = Module.new
|
||||
modules.each do |m|
|
||||
m.module_eval { include modul }
|
||||
end
|
||||
modul
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,12 +0,0 @@
|
||||
require 'set'
|
||||
|
||||
module Tins
|
||||
class NamedSet < Set
|
||||
def initialize(name)
|
||||
@name = name
|
||||
super()
|
||||
end
|
||||
|
||||
attr_accessor :name
|
||||
end
|
||||
end
|
@ -1,101 +0,0 @@
|
||||
module Tins
|
||||
# Implementation of the null object pattern in Ruby.
|
||||
module Null
|
||||
def method_missing(*)
|
||||
self
|
||||
end
|
||||
|
||||
def const_missing(*)
|
||||
self
|
||||
end
|
||||
|
||||
def to_s
|
||||
''
|
||||
end
|
||||
|
||||
def to_str
|
||||
nil
|
||||
end
|
||||
|
||||
def to_f
|
||||
0.0
|
||||
end
|
||||
|
||||
def to_i
|
||||
0
|
||||
end
|
||||
|
||||
def to_int
|
||||
nil
|
||||
end
|
||||
|
||||
def to_a
|
||||
[]
|
||||
end
|
||||
|
||||
def to_ary
|
||||
nil
|
||||
end
|
||||
|
||||
def inspect
|
||||
'NULL'
|
||||
end
|
||||
|
||||
def nil?
|
||||
true
|
||||
end
|
||||
|
||||
def blank?
|
||||
true
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
end
|
||||
|
||||
def to_json(*)
|
||||
'null'
|
||||
end
|
||||
|
||||
module Kernel
|
||||
def null(value = nil)
|
||||
value.nil? ? Tins::NULL : value
|
||||
end
|
||||
|
||||
alias Null null
|
||||
|
||||
def null_plus(opts = {})
|
||||
value = opts[:value]
|
||||
opts[:caller] = caller
|
||||
if respond_to?(:caller_locations, true)
|
||||
opts[:caller_locations] = caller_locations
|
||||
end
|
||||
|
||||
value.nil? ? Tins::NullPlus.new(opts) : value
|
||||
end
|
||||
|
||||
alias NullPlus null_plus
|
||||
end
|
||||
end
|
||||
|
||||
class NullClass < Module
|
||||
include Tins::Null
|
||||
end
|
||||
|
||||
NULL = NullClass.new
|
||||
|
||||
NULL.freeze
|
||||
|
||||
class NullPlus
|
||||
include Tins::Null
|
||||
|
||||
def initialize(opts = {})
|
||||
singleton_class.class_eval do
|
||||
opts.each do |name, value|
|
||||
define_method(name) { value }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,25 +0,0 @@
|
||||
module Tins
|
||||
module Once
|
||||
include File::Constants
|
||||
|
||||
module_function
|
||||
|
||||
def only_once(lock_filename = nil, locking_constant = nil)
|
||||
lock_filename ||= $0
|
||||
locking_constant ||= LOCK_EX
|
||||
f = File.new(lock_filename, RDONLY)
|
||||
f.flock(locking_constant) and yield
|
||||
ensure
|
||||
if f
|
||||
f.flock LOCK_UN
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
def try_only_once(lock_filename = nil, locking_constant = nil, &block)
|
||||
only_once(lock_filename, locking_constant || LOCK_EX | LOCK_NB, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,23 +0,0 @@
|
||||
require 'pp'
|
||||
|
||||
module Tins
|
||||
module P
|
||||
private
|
||||
|
||||
# Raise a runtime error with the inspected objects +objs+ (obtained by
|
||||
# calling the #inspect method) as their message text. This is useful for
|
||||
# quick debugging.
|
||||
def p!(*objs)
|
||||
raise((objs.size < 2 ? objs.first : objs).inspect)
|
||||
end
|
||||
|
||||
# Raise a runtime error with the inspected objects +objs+ (obtained by
|
||||
# calling the #pretty_inspect method) as their message text. This is useful
|
||||
# for quick debugging.
|
||||
def pp!(*objs)
|
||||
raise("\n" + (objs.size < 2 ? objs.first : objs).pretty_inspect.chomp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,31 +0,0 @@
|
||||
module Tins
|
||||
module PartialApplication
|
||||
# If this module is included into a Proc (or similar object), it tampers
|
||||
# with its Proc#arity method.
|
||||
def self.included(modul)
|
||||
modul.module_eval do
|
||||
old_arity = instance_method(:arity)
|
||||
define_method(:arity) do
|
||||
defined?(@__arity__) or old_arity.bind(self).call
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
# Create a partial application of this Proc (or similar object) using
|
||||
# _args_ as the already applied arguments.
|
||||
def partial(*args)
|
||||
if args.empty?
|
||||
dup
|
||||
elsif args.size > arity
|
||||
raise ArgumentError, "wrong number of arguments (#{args.size} for #{arity})"
|
||||
else
|
||||
f = lambda { |*b| call(*(args + b)) }
|
||||
f.instance_variable_set :@__arity__, arity - args.size
|
||||
f
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,15 +0,0 @@
|
||||
module Tins
|
||||
module ProcCompose
|
||||
def compose(other)
|
||||
self.class.new do |*args|
|
||||
if other.respond_to?(:call)
|
||||
call(*other.call(*args))
|
||||
else
|
||||
call(*other.to_proc.call(*args))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alias * compose
|
||||
end
|
||||
end
|
@ -1,73 +0,0 @@
|
||||
require 'tins/memoize'
|
||||
|
||||
module Tins
|
||||
module ProcPrelude
|
||||
def apply(&my_proc)
|
||||
my_proc or raise ArgumentError, 'a block argument is required'
|
||||
lambda { |list| my_proc.call(*list) }
|
||||
end
|
||||
|
||||
def map_apply(my_method, *args, &my_proc)
|
||||
my_proc or raise ArgumentError, 'a block argument is required'
|
||||
lambda { |x, y| my_proc.call(x, y.__send__(my_method, *args)) }
|
||||
end
|
||||
|
||||
def call(obj, &my_proc)
|
||||
my_proc or raise ArgumentError, 'a block argument is required'
|
||||
obj.instance_eval(&my_proc)
|
||||
end
|
||||
|
||||
def array
|
||||
lambda { |*list| list }
|
||||
end
|
||||
memoize_function :array, freeze: true
|
||||
|
||||
def first
|
||||
lambda { |*list| list.first }
|
||||
end
|
||||
memoize_function :first, freeze: true
|
||||
|
||||
alias head first
|
||||
|
||||
def second
|
||||
lambda { |*list| list[1] }
|
||||
end
|
||||
memoize_function :second, freeze: true
|
||||
|
||||
def tail
|
||||
lambda { |*list| list[1..-1] }
|
||||
end
|
||||
memoize_function :tail, freeze: true
|
||||
|
||||
def last
|
||||
lambda { |*list| list.last }
|
||||
end
|
||||
memoize_function :last, freeze: true
|
||||
|
||||
def rotate(n = 1)
|
||||
lambda { |*list| list.rotate(n) }
|
||||
end
|
||||
|
||||
alias swap rotate
|
||||
|
||||
def id1
|
||||
lambda { |obj| obj }
|
||||
end
|
||||
memoize_function :id1, freeze: true
|
||||
|
||||
def const(konst = nil, &my_proc)
|
||||
konst ||= my_proc.call
|
||||
lambda { |*_| konst }
|
||||
end
|
||||
|
||||
def nth(n)
|
||||
lambda { |*list| list[n] }
|
||||
end
|
||||
|
||||
def from(&block)
|
||||
my_method, binding = block.call, block.binding
|
||||
my_self = eval 'self', binding
|
||||
lambda { |*list| my_self.__send__(my_method, *list) }
|
||||
end
|
||||
end
|
||||
end
|
@ -1,9 +0,0 @@
|
||||
module Tins
|
||||
module RangePlus
|
||||
def +(other)
|
||||
to_a + other.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,9 +0,0 @@
|
||||
module Tins
|
||||
module RequireMaybe
|
||||
def require_maybe(library)
|
||||
require library
|
||||
rescue LoadError => e
|
||||
block_given? and yield e
|
||||
end
|
||||
end
|
||||
end
|
@ -1,19 +0,0 @@
|
||||
module Tins
|
||||
module Responding
|
||||
def responding?(*method_names)
|
||||
Class.new do
|
||||
define_method(:to_s) do
|
||||
"Responding to #{method_names * ', '}"
|
||||
end
|
||||
|
||||
alias inspect to_s
|
||||
|
||||
define_method(:===) do |object|
|
||||
method_names.all? do |method_name|
|
||||
object.respond_to?(method_name)
|
||||
end
|
||||
end
|
||||
end.new
|
||||
end
|
||||
end
|
||||
end
|
@ -1,27 +0,0 @@
|
||||
module Tins
|
||||
module SecureWrite
|
||||
# Write to a file atomically
|
||||
def secure_write(filename, content = nil, mode = 'w')
|
||||
temp = File.new(filename + ".tmp.#$$.#{Time.now.to_f}", mode)
|
||||
if content.nil? and block_given?
|
||||
yield temp
|
||||
elsif !content.nil?
|
||||
temp.write content
|
||||
else
|
||||
raise ArgumentError, "either content or block argument required"
|
||||
end
|
||||
temp.fsync
|
||||
size = temp.stat.size
|
||||
temp.close
|
||||
File.rename temp.path, filename
|
||||
size
|
||||
ensure
|
||||
if temp
|
||||
!temp.closed? and temp.close
|
||||
File.file?(temp.path) and File.unlink temp.path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,39 +0,0 @@
|
||||
require 'singleton'
|
||||
|
||||
module Tins
|
||||
|
||||
SexySingleton = Singleton.dup
|
||||
|
||||
module SexySingleton
|
||||
module SingletonClassMethods
|
||||
end
|
||||
end
|
||||
|
||||
class << SexySingleton
|
||||
alias __old_singleton_included__ included
|
||||
|
||||
def included(klass)
|
||||
__old_singleton_included__(klass)
|
||||
(class << klass; self; end).class_eval do
|
||||
if Object.method_defined?(:respond_to_missing?)
|
||||
def respond_to_missing?(name, *args)
|
||||
instance.respond_to?(name) || super
|
||||
end
|
||||
else
|
||||
def respond_to?(name, *args)
|
||||
instance.respond_to?(name) || super
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
if instance.respond_to?(name)
|
||||
instance.__send__(name, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
@ -1,20 +0,0 @@
|
||||
require 'tins/concern'
|
||||
|
||||
module Tins
|
||||
module StringByteOrderMark
|
||||
def bom_encoding
|
||||
prefix = self[0, 4].force_encoding(Encoding::ASCII_8BIT)
|
||||
case prefix
|
||||
when /\A\xef\xbb\xbf/n then Encoding::UTF_8
|
||||
when /\A\x00\x00\xff\xfe/n then Encoding::UTF_32BE
|
||||
when /\A\xff\xfe\x00\x00/n then Encoding::UTF_32LE
|
||||
when /\A\xfe\xff/n then Encoding::UTF_16BE
|
||||
when /\A\xff\xfe/n then Encoding::UTF_16LE
|
||||
when /\A\x2b\x2f\x76[\x38-\x39\x2b\x2f]/n then Encoding::UTF_7
|
||||
when /\A\x84\x31\x95\x33/n then Encoding::GB18030
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,16 +0,0 @@
|
||||
module Tins
|
||||
module StringCamelize
|
||||
def camelize(first_letter = :upper)
|
||||
case first_letter
|
||||
when :upper, true
|
||||
gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
||||
when :lower, false
|
||||
self[0].chr.downcase + camelize[1..-1]
|
||||
end
|
||||
end
|
||||
|
||||
alias camelcase camelize
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,15 +0,0 @@
|
||||
module Tins
|
||||
module StringUnderscore
|
||||
def underscore
|
||||
word = dup
|
||||
word.gsub!(/::/, '/')
|
||||
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
||||
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
||||
word.tr!("-", "_")
|
||||
word.downcase!
|
||||
word
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,104 +0,0 @@
|
||||
module Tins
|
||||
module StringVersion
|
||||
LEVELS = [ :major, :minor, :build, :revision ].each_with_index.
|
||||
each_with_object({}) { |(k, v), h| h[k] = v }.freeze
|
||||
|
||||
SYMBOLS = LEVELS.invert.freeze
|
||||
|
||||
class Version
|
||||
include Comparable
|
||||
|
||||
def initialize(string)
|
||||
string =~ /\A\d+(\.\d+)*\z/ or
|
||||
raise ArgumentError, "#{string.inspect} isn't a version number"
|
||||
@version = string.frozen? ? string.dup : string
|
||||
end
|
||||
|
||||
LEVELS.each do |symbol, level|
|
||||
define_method(symbol) do
|
||||
self[level]
|
||||
end
|
||||
|
||||
define_method("#{symbol}=") do |new_level|
|
||||
self[level] = new_level
|
||||
end
|
||||
end
|
||||
|
||||
def bump(level = array.size - 1)
|
||||
level = level_of(level)
|
||||
self[level] += 1
|
||||
for l in level.succ..3
|
||||
self[l] &&= 0
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def level_of(specifier)
|
||||
if specifier.respond_to?(:to_sym)
|
||||
LEVELS.fetch(specifier)
|
||||
else
|
||||
specifier
|
||||
end
|
||||
end
|
||||
|
||||
def [](level)
|
||||
array[level_of(level)]
|
||||
end
|
||||
|
||||
def []=(level, value)
|
||||
level = level_of(level)
|
||||
value = value.to_i
|
||||
value >= 0 or raise ArgumentError,
|
||||
"version numbers can't contain negative numbers like #{value}"
|
||||
a = array
|
||||
a[level] = value
|
||||
a.map!(&:to_i)
|
||||
@version.replace a * ?.
|
||||
end
|
||||
|
||||
def succ!
|
||||
self[-1] += 1
|
||||
self
|
||||
end
|
||||
|
||||
def pred!
|
||||
self[-1] -= 1
|
||||
self
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
pairs = array.zip(other.array)
|
||||
pairs.map! { |a, b| [ a.to_i, b.to_i ] }
|
||||
a, b = pairs.transpose
|
||||
a <=> b
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
(self <=> other).zero?
|
||||
end
|
||||
|
||||
def array
|
||||
@version.split(?.).map(&:to_i)
|
||||
end
|
||||
|
||||
alias to_a array
|
||||
|
||||
def to_s
|
||||
@version
|
||||
end
|
||||
|
||||
def initialize_copy(source)
|
||||
super
|
||||
@version = source.instance_variable_get(:@version).dup
|
||||
end
|
||||
|
||||
alias inspect to_s
|
||||
end
|
||||
|
||||
def version
|
||||
Version.new(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,42 +0,0 @@
|
||||
module Tins
|
||||
module Subhash
|
||||
# Create a subhash from this hash, that only contains key-value pairs
|
||||
# matching +patterns+ and return it. +patterns+ can be for example /^foo/
|
||||
# to put 'foobar' and 'foobaz' or 'foo'/:foo to put 'foo' into the subhash.
|
||||
#
|
||||
# If a block is given this method yields to it after the first pattern
|
||||
# matched with a 3-tuple of +(key, value, match_data)+ using the return
|
||||
# value of the block as the value of the result hash. +match_data+ is a
|
||||
# MatchData instance if the matching pattern was a regular rexpression
|
||||
# otherwise it is nil.
|
||||
def subhash(*patterns)
|
||||
patterns.map! do |pat|
|
||||
pat = pat.to_sym.to_s if pat.respond_to?(:to_sym)
|
||||
pat.respond_to?(:match) ? pat : pat.to_s
|
||||
end
|
||||
result =
|
||||
if default_proc
|
||||
self.class.new(&default_proc)
|
||||
else
|
||||
self.class.new(default)
|
||||
end
|
||||
if block_given?
|
||||
each do |k, v|
|
||||
patterns.each { |pat|
|
||||
if pat === k.to_s
|
||||
result[k] = yield(k, v, $~)
|
||||
break
|
||||
end
|
||||
}
|
||||
end
|
||||
else
|
||||
each do |k, v|
|
||||
result[k] = v if patterns.any? { |pat| pat === k.to_s }
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,26 +0,0 @@
|
||||
require 'tmpdir'
|
||||
|
||||
module Tins
|
||||
module TempIO
|
||||
def temp_io(content: nil, name: __method__)
|
||||
content.nil? and raise ArgumentError, "missing keyword: content"
|
||||
name = File.basename(name.to_s)
|
||||
Dir.mktmpdir do |dir|
|
||||
name = File.join(dir, name)
|
||||
File.open(name, 'w+b') do |io|
|
||||
if content.respond_to?(:call)
|
||||
if content.respond_to?(:arity) && content.arity == 1
|
||||
content.call(io)
|
||||
else
|
||||
io.write content.call
|
||||
end
|
||||
else
|
||||
io.write content
|
||||
end
|
||||
io.rewind
|
||||
yield io
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,26 +0,0 @@
|
||||
require 'tins/temp_io'
|
||||
|
||||
module Tins
|
||||
module TempIO
|
||||
class Enum < Enumerator
|
||||
include Tins::TempIO
|
||||
|
||||
def initialize(chunk_size: 2 ** 16, filename: nil, &content_proc)
|
||||
content_proc or raise ArgumentError, 'need a content proc as block argument'
|
||||
super() do |y|
|
||||
temp_io(name: 'some-stream', content: content_proc) do |file|
|
||||
until file.eof?
|
||||
y.yield file.read(chunk_size)
|
||||
end
|
||||
end
|
||||
end.tap do |enum|
|
||||
if filename
|
||||
enum.define_singleton_method(:filename) do
|
||||
filename
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,42 +0,0 @@
|
||||
begin
|
||||
require 'io/console'
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
module Tins
|
||||
module Terminal
|
||||
|
||||
module_function
|
||||
|
||||
def winsize
|
||||
if IO.respond_to?(:console)
|
||||
console = IO.console
|
||||
if console.respond_to?(:winsize)
|
||||
console.winsize
|
||||
else
|
||||
[]
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def rows
|
||||
winsize[0] || `stty size 2>/dev/null`.split[0].to_i.nonzero? ||
|
||||
`tput lines 2>/dev/null`.to_i.nonzero? || 25
|
||||
end
|
||||
|
||||
def lines
|
||||
rows
|
||||
end
|
||||
|
||||
def columns
|
||||
winsize[1] || `stty size 2>/dev/null`.split[1].to_i.nonzero? ||
|
||||
`tput cols 2>/dev/null`.to_i.nonzero? || 80
|
||||
end
|
||||
|
||||
def cols
|
||||
columns
|
||||
end
|
||||
end
|
||||
end
|
@ -1,57 +0,0 @@
|
||||
module Tins
|
||||
module ThreadLocal
|
||||
@@mutex = Mutex.new
|
||||
|
||||
@@cleanup = lambda do |my_object_id|
|
||||
my_id = "__thread_local_#{my_object_id}__"
|
||||
@@mutex.synchronize do
|
||||
for t in Thread.list
|
||||
t[my_id] = nil if t[my_id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Define a thread local variable named _name_ in this module/class. If the
|
||||
# value _value_ is given, it is used to initialize the variable.
|
||||
def thread_local(name, default_value = nil, &default)
|
||||
is_a?(Module) or raise TypeError, "receiver has to be a Module"
|
||||
|
||||
default_value && default and raise ArgumentError,
|
||||
"require either default_falue or default block"
|
||||
|
||||
if default_value
|
||||
default = -> * { default_value }
|
||||
end
|
||||
|
||||
name = name.to_s
|
||||
my_id = "__thread_local_#{__id__}__"
|
||||
|
||||
ObjectSpace.define_finalizer(self, @@cleanup)
|
||||
|
||||
define_method(name) do
|
||||
values = Thread.current[my_id] ||= {}
|
||||
if default && !values.key?(name)
|
||||
values[name] = default.call
|
||||
end
|
||||
values[name]
|
||||
end
|
||||
|
||||
define_method("#{name}=") do |value|
|
||||
Thread.current[my_id] ||= {}
|
||||
Thread.current[my_id][name] = value
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Define a thread local variable for the current instance with name _name_.
|
||||
# If the value _value_ is given, it is used to initialize the variable.
|
||||
def instance_thread_local(name, default_value = nil, &default)
|
||||
class << self
|
||||
extend Tins::ThreadLocal
|
||||
self
|
||||
end.thread_local name, default_value, &default
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
@ -1,57 +0,0 @@
|
||||
require 'time'
|
||||
|
||||
module Tins
|
||||
module TimeDummy
|
||||
def self.included(modul)
|
||||
class << modul
|
||||
alias really_new new
|
||||
alias really_now now
|
||||
|
||||
remove_method :now rescue nil
|
||||
remove_method :new rescue nil
|
||||
|
||||
def dummy=(value)
|
||||
if value.respond_to?(:to_str)
|
||||
value = Time.parse(value.to_str)
|
||||
elsif value.respond_to?(:to_time)
|
||||
value = value.to_time
|
||||
end
|
||||
@dummy = value
|
||||
end
|
||||
|
||||
def dummy(value = nil)
|
||||
if value.nil?
|
||||
if defined?(@dummy)
|
||||
@dummy
|
||||
end
|
||||
else
|
||||
begin
|
||||
old_dummy = @dummy
|
||||
self.dummy = value
|
||||
yield
|
||||
ensure
|
||||
self.dummy = old_dummy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def new(*a)
|
||||
if dummy
|
||||
dummy.dup
|
||||
elsif caller.first =~ /`now`/
|
||||
really_now
|
||||
else
|
||||
really_new(*a)
|
||||
end
|
||||
end
|
||||
|
||||
def now
|
||||
new
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,8 +0,0 @@
|
||||
module Tins
|
||||
module To
|
||||
def to(string)
|
||||
shift_width = (string[/\A\s*/]).size
|
||||
string.gsub(/^[^\S\n]{0,#{shift_width}}/, '')
|
||||
end
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
module Tins
|
||||
module ToProc
|
||||
# :nocov:
|
||||
def to_proc
|
||||
lambda do |obj, *args|
|
||||
obj.__send__(self, *args[0..-1])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,36 +0,0 @@
|
||||
require 'securerandom'
|
||||
|
||||
module Tins
|
||||
class Token < String
|
||||
DEFAULT_ALPHABET =
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze
|
||||
|
||||
BASE64_ALPHABET =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".freeze
|
||||
|
||||
BASE64_URL_FILENAME_SAFE_ALPHABET =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".freeze
|
||||
|
||||
BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".freeze
|
||||
|
||||
BASE32_EXTENDED_HEX_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUV".freeze
|
||||
|
||||
BASE16_ALPHABET = "0123456789ABCDEF".freeze
|
||||
|
||||
def initialize(bits: 128, length: nil, alphabet: DEFAULT_ALPHABET, random: SecureRandom)
|
||||
alphabet.size > 1 or raise ArgumentError, 'need at least 2 symbols in alphabet'
|
||||
if length
|
||||
length > 0 or raise ArgumentError, 'length has to be positive'
|
||||
else
|
||||
bits > 0 or raise ArgumentError, 'bits has to be positive'
|
||||
length = (Math.log(1 << bits) / Math.log(alphabet.size)).ceil
|
||||
end
|
||||
self.bits = (Math.log(alphabet.size ** length) / Math.log(2)).floor
|
||||
token = ''
|
||||
length.times { token << alphabet[random.random_number(alphabet.size)] }
|
||||
super token
|
||||
end
|
||||
|
||||
attr_accessor :bits
|
||||
end
|
||||
end
|
@ -1,10 +0,0 @@
|
||||
module Tins
|
||||
module UniqBy
|
||||
def uniq_by(&b)
|
||||
b ||= lambda { |x| x }
|
||||
inject({}) { |h, e| h[b[e]] ||= e; h }.values
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,179 +0,0 @@
|
||||
require 'strscan'
|
||||
require 'bigdecimal'
|
||||
|
||||
module Tins::Unit
|
||||
Prefix = Struct.new(:name, :step, :multiplier, :fraction)
|
||||
|
||||
PREFIX_LC = [
|
||||
'', 'k', 'm', 'g', 't', 'p', 'e', 'z', 'y',
|
||||
].each_with_index.map { |n, i| Prefix.new(n.freeze, 1000, 1000 ** i, false) }.freeze
|
||||
|
||||
PREFIX_UC = [
|
||||
'', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y',
|
||||
].each_with_index.map { |n, i| Prefix.new(n.freeze, 1024, 1024 ** i, false) }.freeze
|
||||
|
||||
PREFIX_F = [
|
||||
'', 'm', 'µ', 'n', 'p', 'f', 'a', 'z', 'y',
|
||||
].each_with_index.map { |n, i| Prefix.new(n.freeze, 1000, 1000 ** -i, true) }.freeze
|
||||
|
||||
class ParserError < ArgumentError; end
|
||||
|
||||
module_function
|
||||
|
||||
def prefixes(identifier)
|
||||
case identifier
|
||||
when :uppercase, :uc, 1024
|
||||
PREFIX_UC
|
||||
when :lowercase, :lc, 1000
|
||||
PREFIX_LC
|
||||
when :fraction, :f, 0.001
|
||||
PREFIX_F
|
||||
when Array
|
||||
identifier
|
||||
end
|
||||
end
|
||||
|
||||
def format(value, format: '%f %U', prefix: 1024, unit: ?b)
|
||||
prefixes = prefixes(prefix)
|
||||
first_prefix = prefixes.first or
|
||||
raise ArgumentError, 'a non-empty array of prefixes is required'
|
||||
if value.zero?
|
||||
result = format.sub('%U', unit)
|
||||
result %= value
|
||||
else
|
||||
prefix = prefixes[
|
||||
(first_prefix.fraction ? -1 : 1) * Math.log(value.abs) / Math.log(first_prefix.step)
|
||||
]
|
||||
result = format.sub('%U', "#{prefix.name}#{unit}")
|
||||
result %= (value / prefix.multiplier.to_f)
|
||||
end
|
||||
end
|
||||
|
||||
class UnitParser < StringScanner
|
||||
NUMBER = /([+-]?
|
||||
(?:0|[1-9]\d*)
|
||||
(?:
|
||||
\.\d+(?i:e[+-]?\d+) |
|
||||
\.\d+ |
|
||||
(?i:e[+-]?\d+)
|
||||
)?
|
||||
)/x
|
||||
|
||||
def initialize(source, unit, prefixes = nil)
|
||||
super source
|
||||
if prefixes
|
||||
@unit_re = unit_re(Tins::Unit.prefixes(prefixes), unit)
|
||||
@unit_lc_re = @unit_uc_re = nil
|
||||
else
|
||||
@unit_lc_re = unit_re(Tins::Unit.prefixes(:lc), unit)
|
||||
@unit_uc_re = unit_re(Tins::Unit.prefixes(:uc), unit)
|
||||
@unit_re = nil
|
||||
end
|
||||
@number = 1.0
|
||||
end
|
||||
|
||||
def unit_re(prefixes, unit)
|
||||
re = Regexp.new(
|
||||
"(#{prefixes.reverse.map { |pre| Regexp.quote(pre.name) } * ?|})(#{unit})"
|
||||
)
|
||||
re.singleton_class.class_eval do
|
||||
define_method(:prefixes) { prefixes }
|
||||
end
|
||||
re
|
||||
end
|
||||
|
||||
private :unit_re
|
||||
|
||||
attr_reader :number
|
||||
|
||||
def scan(re)
|
||||
re.nil? and return
|
||||
super
|
||||
end
|
||||
|
||||
def scan_number
|
||||
scan(NUMBER) or return
|
||||
@number *= BigDecimal(self[1])
|
||||
end
|
||||
|
||||
def scan_unit
|
||||
case
|
||||
when scan(@unit_re)
|
||||
prefix = @unit_re.prefixes.find { |pre| pre.name == self[1] } or return
|
||||
@number *= prefix.multiplier
|
||||
when scan(@unit_lc_re)
|
||||
prefix = @unit_lc_re.prefixes.find { |pre| pre.name == self[1] } or return
|
||||
@number *= prefix.multiplier
|
||||
when scan(@unit_uc_re)
|
||||
prefix = @unit_uc_re.prefixes.find { |pre| pre.name == self[1] } or return
|
||||
@number *= prefix.multiplier
|
||||
end
|
||||
end
|
||||
|
||||
def scan_char(char)
|
||||
scan(/#{char}/) or return
|
||||
end
|
||||
|
||||
def parse
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
class FormatParser < StringScanner
|
||||
def initialize(format, unit_parser)
|
||||
super format
|
||||
@unit_parser = unit_parser
|
||||
end
|
||||
|
||||
def reset
|
||||
super
|
||||
@unit_parser.reset
|
||||
end
|
||||
|
||||
def location
|
||||
@unit_parser.peek(10).inspect
|
||||
end
|
||||
|
||||
private :location
|
||||
|
||||
def parse
|
||||
reset
|
||||
until eos? || @unit_parser.eos?
|
||||
case
|
||||
when scan(/%f/)
|
||||
@unit_parser.scan_number or
|
||||
raise ParserError, "\"%f\" expected at #{location}"
|
||||
when scan(/%U/)
|
||||
@unit_parser.scan_unit or
|
||||
raise ParserError, "\"%U\" expected at #{location}"
|
||||
when scan(/%%/)
|
||||
@unit_parser.scan_char(?%) or
|
||||
raise ParserError, "#{?%.inspect} expected at #{location}"
|
||||
else
|
||||
char = scan(/./)
|
||||
@unit_parser.scan_char(char) or
|
||||
raise ParserError, "#{char.inspect} expected at #{location}"
|
||||
end
|
||||
end
|
||||
unless eos? && @unit_parser.eos?
|
||||
raise ParserError,
|
||||
"format #{string.inspect} and string "\
|
||||
"#{@unit_parser.string.inspect} do not match"
|
||||
end
|
||||
@unit_parser.number
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the string +string+ if it matches +format+ with the unit +unit+ and
|
||||
# the prefixes specified by +prefix+.
|
||||
def parse(string, format: '%f %U', unit: ?b, prefix: nil)
|
||||
prefixes = prefixes(prefix)
|
||||
FormatParser.new(format, UnitParser.new(string, unit, prefixes)).parse
|
||||
end
|
||||
|
||||
def parse?(string, **options)
|
||||
parse(string, **options)
|
||||
rescue ParserError
|
||||
nil
|
||||
end
|
||||
end
|
@ -1,8 +0,0 @@
|
||||
module Tins
|
||||
# Tins version
|
||||
VERSION = '1.25.0'
|
||||
VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
|
||||
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
|
||||
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
|
||||
VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
|
||||
end
|
@ -1,19 +0,0 @@
|
||||
require 'tins/secure_write'
|
||||
|
||||
module Tins
|
||||
module Write
|
||||
def self.extended(modul)
|
||||
modul.extend SecureWrite
|
||||
if modul.respond_to?(:write)
|
||||
$DEBUG and warn "Skipping inclusion of Tins::Write#write method, include Tins::Write::SecureWrite#secure_write instead"
|
||||
else
|
||||
class << modul; self; end.instance_eval do
|
||||
alias_method :write, :secure_write
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'tins/alias'
|
@ -1,45 +0,0 @@
|
||||
require 'tins'
|
||||
|
||||
module Tins
|
||||
require 'tins/xt/attempt'
|
||||
require 'tins/xt/blank'
|
||||
require 'tins/xt/count_by'
|
||||
require 'tins/xt/deep_dup'
|
||||
require 'tins/xt/file_binary'
|
||||
require 'tins/xt/full'
|
||||
require 'tins/xt/hash_symbolize_keys_recursive'
|
||||
require 'tins/xt/hash_union'
|
||||
require 'tins/xt/irb'
|
||||
require 'tins/xt/named'
|
||||
require 'tins/xt/null'
|
||||
require 'tins/xt/p'
|
||||
require 'tins/xt/partial_application'
|
||||
require 'tins/xt/range_plus'
|
||||
require 'tins/xt/require_maybe'
|
||||
require 'tins/xt/secure_write'
|
||||
require 'tins/xt/string'
|
||||
require 'tins/xt/subhash'
|
||||
require 'tins/xt/time_dummy'
|
||||
require 'tins/xt/date_dummy'
|
||||
require 'tins/xt/date_time_dummy'
|
||||
require 'tins/xt/uniq_by'
|
||||
require 'tins/xt/write'
|
||||
require 'tins/xt/if_predicate'
|
||||
require 'tins/xt/ask_and_send'
|
||||
require 'tins/xt/extract_last_argument_options'
|
||||
require 'tins/xt/deep_const_get'
|
||||
require 'tins/xt/responding'
|
||||
require 'tins/xt/proc_compose'
|
||||
require 'tins/xt/proc_prelude'
|
||||
require 'tins/xt/sexy_singleton'
|
||||
require 'tins/xt/method_description'
|
||||
require 'tins/xt/annotate'
|
||||
require 'tins/xt/concern'
|
||||
require 'tins/xt/dslkit'
|
||||
require 'tins/xt/time_freezer'
|
||||
require 'tins/xt/case_predicate'
|
||||
require 'tins/xt/implement'
|
||||
require 'tins/xt/complete'
|
||||
require 'tins/xt/expose'
|
||||
require 'tins/xt/temp_io'
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
require 'tins/annotate'
|
||||
|
||||
class Module
|
||||
include Tins::Annotate
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
require 'tins/ask_and_send'
|
||||
|
||||
module Tins
|
||||
class ::Object
|
||||
include Tins::AskAndSend
|
||||
end
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
require 'tins/attempt'
|
||||
|
||||
module Tins
|
||||
class ::Object
|
||||
include Tins::Attempt
|
||||
end
|
||||
end
|
@ -1,67 +0,0 @@
|
||||
module Tins
|
||||
module Blank
|
||||
module Object
|
||||
def blank?
|
||||
respond_to?(:empty?) ? empty? : !self
|
||||
end
|
||||
|
||||
def present?
|
||||
!blank?
|
||||
end
|
||||
end
|
||||
|
||||
module NilClass
|
||||
def blank?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
module FalseClass
|
||||
def blank?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
module TrueClass
|
||||
def blank?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
module Array
|
||||
def self.included(modul)
|
||||
modul.module_eval do
|
||||
alias_method :blank?, :empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Hash
|
||||
def self.included(modul)
|
||||
modul.module_eval do
|
||||
alias_method :blank?, :empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module String
|
||||
def blank?
|
||||
self !~ /\S/
|
||||
end
|
||||
end
|
||||
|
||||
module Numeric
|
||||
def blank?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unless Object.respond_to?(:blank?)
|
||||
for k in Tins::Blank.constants
|
||||
Object.const_get(k).class_eval do
|
||||
include Tins::Blank.const_get(k)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,8 +0,0 @@
|
||||
require 'tins/case_predicate'
|
||||
|
||||
module Tins
|
||||
class ::Object
|
||||
include Tins::CasePredicate
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +0,0 @@
|
||||
require 'tins/complete'
|
||||
|
||||
module Tins
|
||||
class ::Object
|
||||
include Tins::Complete
|
||||
end
|
||||
end
|
@ -1,20 +0,0 @@
|
||||
require 'tins/concern'
|
||||
|
||||
module Tins
|
||||
module Concern
|
||||
module ModuleMixin
|
||||
def tins_concern_configure(*args)
|
||||
Thread.current[:tin_concern_args] = args
|
||||
self
|
||||
end
|
||||
|
||||
def tins_concern_args
|
||||
Thread.current[:tin_concern_args]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ::Module
|
||||
include Tins::Concern::ModuleMixin
|
||||
end
|
||||
end
|
@ -1,11 +0,0 @@
|
||||
require 'tins/count_by'
|
||||
|
||||
module Tins
|
||||
module ::Enumerable
|
||||
include CountBy
|
||||
end
|
||||
|
||||
class ::Array
|
||||
include CountBy
|
||||
end
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
require 'tins/date_dummy'
|
||||
|
||||
module Tins
|
||||
class ::Date
|
||||
include DateDummy
|
||||
end
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
require 'tins/date_time_dummy'
|
||||
|
||||
module Tins
|
||||
class ::DateTime
|
||||
include DateTimeDummy
|
||||
end
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
require 'tins/deep_const_get'
|
||||
|
||||
module Tins
|
||||
class ::Object
|
||||
include DeepConstGet
|
||||
end
|
||||
end
|
@ -1,7 +0,0 @@
|
||||
require 'tins/deep_dup'
|
||||
|
||||
module Tins
|
||||
class ::Object
|
||||
include Tins::DeepDup
|
||||
end
|
||||
end
|
@ -1,22 +0,0 @@
|
||||
require 'tins'
|
||||
|
||||
module Tins
|
||||
class ::Module
|
||||
include Tins::Constant
|
||||
include Tins::DSLAccessor
|
||||
include Tins::ClassMethod
|
||||
include Tins::Delegate
|
||||
include Tins::ParameterizedModule
|
||||
include Tins::FromModule
|
||||
end
|
||||
|
||||
class ::Object
|
||||
include Tins::ThreadLocal
|
||||
include Tins::ThreadGlobal
|
||||
include Tins::Interpreter
|
||||
include Tins::Deflect
|
||||
include Tins::ThreadLocal
|
||||
include Tins::Eigenclass
|
||||
include Tins::BlockSelf
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user