This commit is contained in:
Baffour Adu Boampong 2020-07-06 13:59:04 +00:00
parent 891030227e
commit e62a0c65ef
136 changed files with 9 additions and 5805 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,3 +0,0 @@
module Coveralls
VERSION = "0.8.23"
end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,2 +0,0 @@
require 'tins/alias'
require 'tins/dslkit/polite'

View File

@ -1 +0,0 @@
require 'tins/dslkit'

View File

@ -1 +0,0 @@
require 'tins/xt/dslkit'

View File

@ -1,2 +0,0 @@
require 'tins'
require 'tins/alias'

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,7 +0,0 @@
module Tins
module CasePredicate
def case?(*args)
args.find { |a| a === self }
end
end
end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -1,7 +0,0 @@
module Tins
module IfPredicate
def if?
self ? self : nil
end
end
end

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -1,12 +0,0 @@
require 'set'
module Tins
class NamedSet < Set
def initialize(name)
@name = name
super()
end
attr_accessor :name
end
end

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -1,9 +0,0 @@
module Tins
module RangePlus
def +(other)
to_a + other.to_a
end
end
end
require 'tins/alias'

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -1,5 +0,0 @@
require 'tins/annotate'
class Module
include Tins::Annotate
end

View File

@ -1,7 +0,0 @@
require 'tins/ask_and_send'
module Tins
class ::Object
include Tins::AskAndSend
end
end

View File

@ -1,7 +0,0 @@
require 'tins/attempt'
module Tins
class ::Object
include Tins::Attempt
end
end

View File

@ -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

View File

@ -1,8 +0,0 @@
require 'tins/case_predicate'
module Tins
class ::Object
include Tins::CasePredicate
end
end

View File

@ -1,7 +0,0 @@
require 'tins/complete'
module Tins
class ::Object
include Tins::Complete
end
end

View File

@ -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

View File

@ -1,11 +0,0 @@
require 'tins/count_by'
module Tins
module ::Enumerable
include CountBy
end
class ::Array
include CountBy
end
end

View File

@ -1,7 +0,0 @@
require 'tins/date_dummy'
module Tins
class ::Date
include DateDummy
end
end

View File

@ -1,7 +0,0 @@
require 'tins/date_time_dummy'
module Tins
class ::DateTime
include DateTimeDummy
end
end

View File

@ -1,7 +0,0 @@
require 'tins/deep_const_get'
module Tins
class ::Object
include DeepConstGet
end
end

View File

@ -1,7 +0,0 @@
require 'tins/deep_dup'
module Tins
class ::Object
include Tins::DeepDup
end
end

View File

@ -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