tins 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/.travis.yml +7 -0
- data/Gemfile +5 -0
- data/LICENSE +18 -0
- data/README.rdoc +20 -0
- data/Rakefile +28 -0
- data/TODO +1 -0
- data/VERSION +1 -0
- data/lib/spruz.rb +1 -0
- data/lib/tins.rb +34 -0
- data/lib/tins/alias.rb +1 -0
- data/lib/tins/attempt.rb +51 -0
- data/lib/tins/bijection.rb +46 -0
- data/lib/tins/count_by.rb +8 -0
- data/lib/tins/deep_dup.rb +11 -0
- data/lib/tins/file_binary.rb +85 -0
- data/lib/tins/generator.rb +68 -0
- data/lib/tins/go.rb +43 -0
- data/lib/tins/hash_symbolize_keys_recursive.rb +28 -0
- data/lib/tins/hash_union.rb +15 -0
- data/lib/tins/limited.rb +38 -0
- data/lib/tins/lines_file.rb +123 -0
- data/lib/tins/memoize.rb +78 -0
- data/lib/tins/minimize.rb +55 -0
- data/lib/tins/module_group.rb +13 -0
- data/lib/tins/null.rb +26 -0
- data/lib/tins/once.rb +25 -0
- data/lib/tins/p.rb +23 -0
- data/lib/tins/partial_application.rb +31 -0
- data/lib/tins/range_plus.rb +9 -0
- data/lib/tins/round.rb +51 -0
- data/lib/tins/secure_write.rb +25 -0
- data/lib/tins/shuffle.rb +17 -0
- data/lib/tins/string_camelize.rb +16 -0
- data/lib/tins/string_underscore.rb +15 -0
- data/lib/tins/string_version.rb +105 -0
- data/lib/tins/subhash.rb +42 -0
- data/lib/tins/time_dummy.rb +31 -0
- data/lib/tins/to_proc.rb +11 -0
- data/lib/tins/uniq_by.rb +10 -0
- data/lib/tins/version.rb +10 -0
- data/lib/tins/write.rb +19 -0
- data/lib/tins/xt.rb +25 -0
- data/lib/tins/xt/attempt.rb +7 -0
- data/lib/tins/xt/blank.rb +67 -0
- data/lib/tins/xt/count_by.rb +11 -0
- data/lib/tins/xt/deep_dup.rb +7 -0
- data/lib/tins/xt/file_binary.rb +7 -0
- data/lib/tins/xt/full.rb +33 -0
- data/lib/tins/xt/hash_symbolize_keys_recursive.rb +7 -0
- data/lib/tins/xt/hash_union.rb +11 -0
- data/lib/tins/xt/irb.rb +17 -0
- data/lib/tins/xt/named.rb +35 -0
- data/lib/tins/xt/null.rb +5 -0
- data/lib/tins/xt/p.rb +7 -0
- data/lib/tins/xt/partial_application.rb +11 -0
- data/lib/tins/xt/range_plus.rb +12 -0
- data/lib/tins/xt/round.rb +13 -0
- data/lib/tins/xt/secure_write.rb +11 -0
- data/lib/tins/xt/shuffle.rb +11 -0
- data/lib/tins/xt/string.rb +5 -0
- data/lib/tins/xt/string_camelize.rb +6 -0
- data/lib/tins/xt/string_underscore.rb +6 -0
- data/lib/tins/xt/string_version.rb +7 -0
- data/lib/tins/xt/subhash.rb +11 -0
- data/lib/tins/xt/symbol_to_proc.rb +7 -0
- data/lib/tins/xt/time_dummy.rb +7 -0
- data/lib/tins/xt/uniq_by.rb +15 -0
- data/lib/tins/xt/write.rb +11 -0
- data/tests/tins_file_binary_test.rb +67 -0
- data/tests/tins_lines_file_test.rb +84 -0
- data/tests/tins_memoize_test.rb +52 -0
- data/tests/tins_secure_write_test.rb +44 -0
- data/tests/tins_test.rb +629 -0
- data/tins.gemspec +35 -0
- metadata +212 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2010 Florian Frank
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
|
16
|
+
CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
17
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
= Tins - Useful tools library in Ruby
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Non yet.
|
6
|
+
|
7
|
+
== Download
|
8
|
+
|
9
|
+
The homepage of this library is located at
|
10
|
+
|
11
|
+
* http://flori.github.com/tins
|
12
|
+
|
13
|
+
== Author
|
14
|
+
|
15
|
+
Florian Frank mailto:flori@ping.de
|
16
|
+
|
17
|
+
== License
|
18
|
+
|
19
|
+
This software is licensed under the X11 (or MIT) license:
|
20
|
+
http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# vim: set filetype=ruby et sw=2 ts=2:
|
2
|
+
|
3
|
+
require 'gem_hadar'
|
4
|
+
|
5
|
+
GemHadar do
|
6
|
+
name 'tins'
|
7
|
+
author 'Florian Frank'
|
8
|
+
email 'flori@ping.de'
|
9
|
+
homepage "http://flori.github.com/#{name}"
|
10
|
+
summary 'Useful stuff.'
|
11
|
+
description 'All the stuff that isn\'t good/big enough for a real library.'
|
12
|
+
test_dir 'tests'
|
13
|
+
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc'
|
14
|
+
readme 'README.rdoc'
|
15
|
+
development_dependency 'test-unit', '~>2.3'
|
16
|
+
|
17
|
+
install_library do
|
18
|
+
libdir = CONFIG["sitelibdir"]
|
19
|
+
cd 'lib' do
|
20
|
+
for file in Dir['**/*.rb']
|
21
|
+
dst = File.join(libdir, file)
|
22
|
+
mkdir_p File.dirname(dst)
|
23
|
+
install file, dst
|
24
|
+
end
|
25
|
+
end
|
26
|
+
install 'bin/enum', File.join(CONFIG['bindir'], 'enum')
|
27
|
+
end
|
28
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
- Ruby1.9 has File.write method now, that conflicts with Tins::Write module's and has to be fixed in some way
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/lib/spruz.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'tins/alias'
|
data/lib/tins.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Tins
|
2
|
+
require 'tins/attempt'
|
3
|
+
require 'tins/bijection'
|
4
|
+
require 'tins/count_by'
|
5
|
+
require 'tins/deep_dup'
|
6
|
+
require 'tins/file_binary'
|
7
|
+
require 'tins/generator'
|
8
|
+
require 'tins/go'
|
9
|
+
require 'tins/hash_symbolize_keys_recursive'
|
10
|
+
require 'tins/hash_union'
|
11
|
+
require 'tins/limited'
|
12
|
+
require 'tins/lines_file'
|
13
|
+
require 'tins/memoize'
|
14
|
+
require 'tins/minimize'
|
15
|
+
require 'tins/module_group'
|
16
|
+
require 'tins/null'
|
17
|
+
require 'tins/once'
|
18
|
+
require 'tins/p'
|
19
|
+
require 'tins/partial_application'
|
20
|
+
require 'tins/range_plus'
|
21
|
+
require 'tins/round'
|
22
|
+
require 'tins/secure_write'
|
23
|
+
require 'tins/shuffle'
|
24
|
+
require 'tins/string_camelize'
|
25
|
+
require 'tins/string_underscore'
|
26
|
+
require 'tins/string_version'
|
27
|
+
require 'tins/subhash'
|
28
|
+
require 'tins/time_dummy'
|
29
|
+
require 'tins/to_proc'
|
30
|
+
require 'tins/uniq_by'
|
31
|
+
require 'tins/version'
|
32
|
+
require 'tins/write'
|
33
|
+
end
|
34
|
+
require 'tins/alias'
|
data/lib/tins/alias.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Spruz = Tins
|
data/lib/tins/attempt.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Tins
|
2
|
+
module Attempt
|
3
|
+
def attempt(opts = {}, &block)
|
4
|
+
sleep = nil
|
5
|
+
exception_class = StandardError
|
6
|
+
if Numeric === opts
|
7
|
+
attempts = opts
|
8
|
+
else
|
9
|
+
attempts = opts[:attempts] || 1
|
10
|
+
exception_class = opts[:exception_class] if opts.key?(:exception_class)
|
11
|
+
sleep = opts[:sleep]
|
12
|
+
end
|
13
|
+
return if attempts <= 0
|
14
|
+
count = 0
|
15
|
+
if exception_class.nil?
|
16
|
+
begin
|
17
|
+
count += 1
|
18
|
+
if block.call(count)
|
19
|
+
return true
|
20
|
+
elsif count < attempts
|
21
|
+
sleep_duration(sleep, count)
|
22
|
+
end
|
23
|
+
end until count == attempts
|
24
|
+
false
|
25
|
+
else
|
26
|
+
begin
|
27
|
+
count += 1
|
28
|
+
block.call(count)
|
29
|
+
true
|
30
|
+
rescue exception_class
|
31
|
+
if count < attempts
|
32
|
+
sleep_duration(sleep, count)
|
33
|
+
retry
|
34
|
+
end
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def sleep_duration(duration, count)
|
43
|
+
case duration
|
44
|
+
when Numeric
|
45
|
+
sleep duration
|
46
|
+
when Proc
|
47
|
+
sleep duration.call(count)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Tins
|
2
|
+
class Bijection < Hash
|
3
|
+
def self.[](*pairs)
|
4
|
+
pairs.size % 2 == 0 or
|
5
|
+
raise ArgumentError, "odd number of arguments for #{self}"
|
6
|
+
new.fill do |obj|
|
7
|
+
(pairs.size / 2).times do |i|
|
8
|
+
j = 2 * i
|
9
|
+
key = pairs[j]
|
10
|
+
value = pairs[j + 1]
|
11
|
+
obj.key?(key) and raise ArgumentError, "duplicate key #{key.inspect} for #{self}"
|
12
|
+
obj.inverted.key?(value) and raise ArgumentError, "duplicate value #{value.inspect} for #{self}"
|
13
|
+
obj[pairs[j]] = pairs[j + 1]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(inverted = Bijection.new(self))
|
19
|
+
@inverted = inverted
|
20
|
+
end
|
21
|
+
|
22
|
+
def fill
|
23
|
+
if empty?
|
24
|
+
yield self
|
25
|
+
freeze
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def freeze
|
31
|
+
r = super
|
32
|
+
unless @inverted.frozen?
|
33
|
+
@inverted.freeze
|
34
|
+
end
|
35
|
+
r
|
36
|
+
end
|
37
|
+
|
38
|
+
def []=(key, value)
|
39
|
+
key?(key) and return
|
40
|
+
super
|
41
|
+
@inverted[value] = key
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :inverted
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'tins/xt/hash_union'
|
2
|
+
|
3
|
+
module Tins
|
4
|
+
module FileBinary
|
5
|
+
module Constants
|
6
|
+
SEEK_SET = ::File::SEEK_SET
|
7
|
+
|
8
|
+
ZERO = "\x00"
|
9
|
+
BINARY = "\x01-\x1f\x7f-\xff"
|
10
|
+
|
11
|
+
if defined?(::Encoding)
|
12
|
+
ZERO.force_encoding(Encoding::ASCII_8BIT)
|
13
|
+
BINARY.force_encoding(Encoding::ASCII_8BIT)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Default options can be queried/set via this hash.
|
19
|
+
attr_accessor :default_options
|
20
|
+
end
|
21
|
+
self.default_options = {
|
22
|
+
:offset => 0,
|
23
|
+
:buffer_size => 2 ** 13,
|
24
|
+
:percentage_binary => 30.0,
|
25
|
+
:percentage_zeros => 0.0,
|
26
|
+
}
|
27
|
+
|
28
|
+
# Returns true if this file is considered to be binary, false if it is not
|
29
|
+
# considered to be binary, and nil if it was empty.
|
30
|
+
#
|
31
|
+
# A file is considered to be binary if the percentage of zeros exceeds
|
32
|
+
# <tt>options[:percentage_zeros]</tt> or the percentage of binary bytes
|
33
|
+
# (8-th bit is 1) exceeds <tt>options[:percentage_binary]</tt> in the
|
34
|
+
# buffer of size <tt>options[:buffer_size]</tt> that is checked (beginning
|
35
|
+
# from offset <tt>options[:offset]</tt>). If an option isn't given the one
|
36
|
+
# from FileBinary.default_options is used instead.
|
37
|
+
def binary?(options = {})
|
38
|
+
options |= FileBinary.default_options
|
39
|
+
old_pos = tell
|
40
|
+
seek options[:offset], Constants::SEEK_SET
|
41
|
+
data = read options[:buffer_size]
|
42
|
+
!data or data.empty? and return nil
|
43
|
+
data_size = data.size
|
44
|
+
data.count(Constants::ZERO).to_f / data_size >
|
45
|
+
options[:percentage_zeros] / 100.0 and return true
|
46
|
+
data.count(Constants::BINARY).to_f / data_size >
|
47
|
+
options[:percentage_binary] / 100.0
|
48
|
+
ensure
|
49
|
+
old_pos and seek old_pos, Constants::SEEK_SET
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns true if FileBinary#binary? returns false, false if
|
53
|
+
# FileBinary#binary? returns true, and nil otherwise. For an explanation of
|
54
|
+
# +options+, see FileBinary#binary?.
|
55
|
+
def ascii?(options = {})
|
56
|
+
case binary?(options)
|
57
|
+
when true then false
|
58
|
+
when false then true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.included(modul)
|
63
|
+
modul.instance_eval do
|
64
|
+
extend ClassMethods
|
65
|
+
end
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
module ClassMethods
|
70
|
+
# Returns true if the file with name +name+ is considered to be binary
|
71
|
+
# using the FileBinary#binary? method.
|
72
|
+
def binary?(name, options = {})
|
73
|
+
open(name, 'rb') { |f| f.binary?(options) }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns true if the file with name +name+ is considered to be ascii
|
77
|
+
# using the FileBinary#ascii? method.
|
78
|
+
def ascii?(name, options = {})
|
79
|
+
open(name, 'rb') { |f| f.ascii?(options) }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
require 'tins/alias'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Tins
|
2
|
+
# This class can create generator objects, that can produce all tuples, that
|
3
|
+
# would be created by as many for-loops as dimensions were given.
|
4
|
+
#
|
5
|
+
# The generator
|
6
|
+
# g = Tins::Generator[1..2, %w[a b c]]
|
7
|
+
# produces
|
8
|
+
# g.to_a # => [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"]]
|
9
|
+
#
|
10
|
+
# The 'each' method can be used to iterate over the tuples
|
11
|
+
# g.each { |a, b| puts "#{a} #{b}" }
|
12
|
+
# and Tins::Generator includes the Enumerable module, so
|
13
|
+
# Enumerable.instance_methods can be used as well:
|
14
|
+
# g.select { |a, b| %w[a c].include? b } # => [[1, "a"], [1, "c"], [2, "a"], [2, "c"]]
|
15
|
+
#
|
16
|
+
class Generator
|
17
|
+
include Enumerable
|
18
|
+
|
19
|
+
# Create a new Generator object from the enumberables _enums_.
|
20
|
+
def self.[](*enums)
|
21
|
+
new(enums)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Create a new Generator instance. Use the objects in the Array _enums_
|
25
|
+
# as dimensions. The should all respond to the :each method (see module
|
26
|
+
# Enumerable in the core ruby library).
|
27
|
+
def initialize(enums)
|
28
|
+
@enums, @iterators, @n = [], [], 0
|
29
|
+
enums.each { |e| add_dimension(e) }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Iterate over all tuples produced by this generator and yield to them.
|
33
|
+
def each(&block) # :yield: tuple
|
34
|
+
recurse(&block)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def recurse(tuple = [ nil ] * @n, i = 0, &block)
|
39
|
+
if i < @n - 1 then
|
40
|
+
@enums[i].__send__(@iterators[i]) do |x|
|
41
|
+
tuple[i] = x
|
42
|
+
recurse(tuple, i + 1, &block)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
@enums[i].__send__(@iterators[i]) do |x|
|
46
|
+
tuple[i] = x
|
47
|
+
yield tuple.dup
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
private :recurse
|
52
|
+
|
53
|
+
# Add another dimension to this generator. _enum_ is an object, that ought
|
54
|
+
# to respond to the _iterator_ method (defaults to :each).
|
55
|
+
def add_dimension(enum, iterator = :each)
|
56
|
+
@enums << enum
|
57
|
+
@iterators << iterator
|
58
|
+
@n += 1
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return the size of this generator, that is the number of its dimensions.
|
62
|
+
def size
|
63
|
+
@enums.size
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
require 'tins/alias'
|
data/lib/tins/go.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Tins
|
2
|
+
module GO
|
3
|
+
module_function
|
4
|
+
|
5
|
+
# Parses the argument array _args_, according to the pattern _s_, to
|
6
|
+
# retrieve the single character command line options from it. If _s_ is
|
7
|
+
# 'xy:' an option '-x' without an option argument is searched, and an
|
8
|
+
# option '-y foo' with an option argument ('foo').
|
9
|
+
#
|
10
|
+
# An option hash is returned with all found options set to true or the
|
11
|
+
# found option argument.
|
12
|
+
def go(s, args = ARGV)
|
13
|
+
b,v = s.scan(/(.)(:?)/).inject([{},{}]) { |t,(o,a)|
|
14
|
+
a = a == ':'
|
15
|
+
t[a ? 1 : 0][o] = a ? nil : false
|
16
|
+
t
|
17
|
+
}
|
18
|
+
while a = args.shift
|
19
|
+
a !~ /\A-(.+)/ and args.unshift a and break
|
20
|
+
p = $1
|
21
|
+
until p == ''
|
22
|
+
o = p.slice!(0, 1)
|
23
|
+
if v.key?(o)
|
24
|
+
if p == '' then
|
25
|
+
v[o] = args.shift or break 1
|
26
|
+
else
|
27
|
+
v[0] = p
|
28
|
+
end
|
29
|
+
break
|
30
|
+
elsif b.key?(o)
|
31
|
+
b[o] = true
|
32
|
+
else
|
33
|
+
args.unshift a
|
34
|
+
break 1
|
35
|
+
end
|
36
|
+
end and break
|
37
|
+
end
|
38
|
+
b.merge(v)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
require 'tins/alias'
|