splib 1.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/CHANGELOG +2 -0
- data/LICENSE +19 -0
- data/README.rdoc +38 -0
- data/lib/splib.rb +32 -0
- data/lib/splib/CodeReloader.rb +54 -0
- data/lib/splib/Constants.rb +21 -0
- data/lib/splib/Conversions.rb +45 -0
- data/lib/splib/Exec.rb +35 -0
- data/lib/splib/HumanIdealRandomIterator.rb +40 -0
- data/lib/splib/PriorityQueue.rb +98 -0
- data/lib/splib/UrlShorteners.rb +48 -0
- data/splib.gemspec +15 -0
- data/tests/cases/CodeReloader.rb +38 -0
- data/tests/cases/Constants.rb +27 -0
- data/tests/cases/Conversions.rb +57 -0
- data/tests/cases/Exec.rb +18 -0
- data/tests/cases/HumanIdealRandomIterator.rb +30 -0
- data/tests/cases/PriorityQueue.rb +45 -0
- data/tests/cases/UrlShorteners.rb +24 -0
- data/tests/run_tests.rb +6 -0
- data/tests/samplecode1.rb +7 -0
- data/tests/samplecode2.rb +7 -0
- metadata +81 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2009 spox <spox@modspox.com>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all 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
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
== Spox Library (splib)
|
|
2
|
+
|
|
3
|
+
The Spox Library is collection of helper methods and classes.
|
|
4
|
+
|
|
5
|
+
=== install (easy):
|
|
6
|
+
|
|
7
|
+
gem install splib
|
|
8
|
+
|
|
9
|
+
=== install (less easy):
|
|
10
|
+
|
|
11
|
+
git clone http://github.com/spox/splib.git
|
|
12
|
+
cd splib
|
|
13
|
+
gem build *.gemspec
|
|
14
|
+
gem install ./
|
|
15
|
+
|
|
16
|
+
=== install (less easy that's a little easier)
|
|
17
|
+
|
|
18
|
+
{rip}[http://hellorip.com/about.html] makes it easy to install directly from a github repository.
|
|
19
|
+
|
|
20
|
+
=== Usage
|
|
21
|
+
|
|
22
|
+
The Spox Library has various things located within it. The Splib#load method will allow you to load individual parts of the library, or the entire thing into your program.
|
|
23
|
+
|
|
24
|
+
require 'splib'
|
|
25
|
+
|
|
26
|
+
Splib.load :UrlShorteners
|
|
27
|
+
puts Splib.tinyurl 'www.google.com'
|
|
28
|
+
|
|
29
|
+
=> "http://tinyurl.com/2ty"
|
|
30
|
+
|
|
31
|
+
== Last remarks
|
|
32
|
+
|
|
33
|
+
If you find any bugs, please report them through {github}[http://github.com/spox/splib/issues]. If you are in need of any help, you can generally find me on DALnet and Freenode.
|
|
34
|
+
|
|
35
|
+
== License
|
|
36
|
+
|
|
37
|
+
Spox Library is licensed under the MIT License
|
|
38
|
+
Copyright (c) 2009 spox <spox@modspox.com>
|
data/lib/splib.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Splib
|
|
2
|
+
LIBS = [:CodeReloader,
|
|
3
|
+
:Constants,
|
|
4
|
+
:Conversions,
|
|
5
|
+
:Exec,
|
|
6
|
+
:HumanIdealRandomIterator,
|
|
7
|
+
:PriorityQueue,
|
|
8
|
+
:UrlShorteners
|
|
9
|
+
]
|
|
10
|
+
# args:: name of library to load
|
|
11
|
+
# Loads the given library. Currently available:
|
|
12
|
+
# :CodeReloader
|
|
13
|
+
# :Constants
|
|
14
|
+
# :Conversions
|
|
15
|
+
# :Exec
|
|
16
|
+
# :HumanIdealRandomIterator
|
|
17
|
+
# :PriorityQueue
|
|
18
|
+
# :UrlShorteners
|
|
19
|
+
# :all
|
|
20
|
+
def self.load(*args)
|
|
21
|
+
if(args.include?(:all))
|
|
22
|
+
LIBS.each do |lib|
|
|
23
|
+
require "splib/#{lib}"
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
args.each do |lib|
|
|
27
|
+
raise NameError.new("Unknown library name: #{lib}") unless LIBS.include?(lib)
|
|
28
|
+
require "splib/#{lib}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Splib
|
|
2
|
+
# path:: path to ruby file
|
|
3
|
+
# type:: return constants only of given type
|
|
4
|
+
# Find all constants in a given ruby file. Array of
|
|
5
|
+
# symbols is returned
|
|
6
|
+
def self.discover_constants(path, type=nil)
|
|
7
|
+
raise ArgumentError.new('Failed to locate plugin file') unless File.exists?(path)
|
|
8
|
+
consts = []
|
|
9
|
+
sandbox = Module.new
|
|
10
|
+
sandbox.module_eval(IO.binread(path))
|
|
11
|
+
sandbox.constants.each do |const|
|
|
12
|
+
klass = sandbox.const_get(const)
|
|
13
|
+
if(type.nil? || (type && klass < type))
|
|
14
|
+
sklass = klass.to_s.slice(klass.to_s.rindex(':')+1, klass.to_s.length)
|
|
15
|
+
consts << sklass.to_sym
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
return consts
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# path:: path to ruby file
|
|
22
|
+
# holder:: module holding loaded ruby code
|
|
23
|
+
# Load code from a ruby file into a module
|
|
24
|
+
def self.load_code(path, holder=nil)
|
|
25
|
+
if(holder)
|
|
26
|
+
raise ArgumentError.new('Expecting a module containing loaded code') unless holder.respond_to?(:path)
|
|
27
|
+
else
|
|
28
|
+
holder = self.create_holder(path)
|
|
29
|
+
end
|
|
30
|
+
holder.module_eval(IO.binread(path))
|
|
31
|
+
holder
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# holder:: module holding loaded ruby code
|
|
35
|
+
# Reload the code within the module
|
|
36
|
+
def self.reload_code(holder)
|
|
37
|
+
raise ArgumentError.new('Expecting a module containing loaded code') unless holder.respond_to?(:path)
|
|
38
|
+
holder.constants.each do |const|
|
|
39
|
+
holder.send(:remove_const, const)
|
|
40
|
+
end
|
|
41
|
+
self.load_code(holder.path, holder)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# path:: path to ruby code
|
|
45
|
+
# Creates a module to hold loaded code
|
|
46
|
+
def self.create_holder(path)
|
|
47
|
+
return Module.new do
|
|
48
|
+
@path = path
|
|
49
|
+
def self.path
|
|
50
|
+
@path
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Splib
|
|
2
|
+
# c:: constant name (String)
|
|
3
|
+
# things:: Array of Object/Module constants to look in
|
|
4
|
+
# Finds a constant if it exists
|
|
5
|
+
# Example:: Foo::Bar
|
|
6
|
+
def self.find_const(c, things=[])
|
|
7
|
+
raise ArgumentError.new('Exepcting an array') unless things.is_a?(Array)
|
|
8
|
+
const = nil
|
|
9
|
+
(things + [Object]).each do |base|
|
|
10
|
+
begin
|
|
11
|
+
c.split('::').each do |part|
|
|
12
|
+
const = const.nil? ? base.const_get(part) : const.const_get(part)
|
|
13
|
+
end
|
|
14
|
+
rescue NameError
|
|
15
|
+
const = nil
|
|
16
|
+
end
|
|
17
|
+
break unless const.nil?
|
|
18
|
+
end
|
|
19
|
+
const.nil? ? c : const
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Splib
|
|
2
|
+
# secs:: number of seconds
|
|
3
|
+
# Converts seconds into a human readable string (This is an estimate
|
|
4
|
+
# and does not account for leaps)
|
|
5
|
+
def self.format_seconds(secs)
|
|
6
|
+
arg = {:year => 31536000,
|
|
7
|
+
:month => 2678400,
|
|
8
|
+
:week => 604800,
|
|
9
|
+
:day => 86400,
|
|
10
|
+
:hour => 3600,
|
|
11
|
+
:minute => 60,
|
|
12
|
+
:second => 1}
|
|
13
|
+
res = ''
|
|
14
|
+
arg.each_pair do |k,v|
|
|
15
|
+
z = (secs / v).to_i
|
|
16
|
+
next unless z > 0
|
|
17
|
+
res += " #{z} #{k}#{z == 1 ? '':'s'}"
|
|
18
|
+
secs = secs % v
|
|
19
|
+
end
|
|
20
|
+
res = '0 seconds' if res.empty?
|
|
21
|
+
return res.strip
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# bytes:: number of bytes
|
|
25
|
+
# Converts bytes into easy human readable form
|
|
26
|
+
# O(1) version by Ryan "pizza_milkshake" Flynn
|
|
27
|
+
Suff = [
|
|
28
|
+
"", # 1024^0
|
|
29
|
+
"Kilo", # 1024^1
|
|
30
|
+
"Mega", # 1024^2
|
|
31
|
+
"Giga", # 1024^3
|
|
32
|
+
"Tera", # 1024^4
|
|
33
|
+
"Peta", # 1024^5
|
|
34
|
+
"Exa", # 1024^6
|
|
35
|
+
"Zetta", # 1024^7
|
|
36
|
+
"Yotta" # 1024^8
|
|
37
|
+
]
|
|
38
|
+
def self.format_size(bytes)
|
|
39
|
+
return "0 bytes" if bytes == 0
|
|
40
|
+
mag = (Math.log(bytes) / Math.log(1024)).floor
|
|
41
|
+
mag = [ Suff.length - 1, mag ].min
|
|
42
|
+
val = bytes.to_f / (1024 ** mag)
|
|
43
|
+
("%.2f %sbyte%s" % [ val, Suff[mag], val == 1 ? "" : "s" ]).strip
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/splib/Exec.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
module Splib
|
|
4
|
+
# command:: command to execute
|
|
5
|
+
# timeout:: maximum number of seconds to run
|
|
6
|
+
# maxbytes:: maximum number of result bytes to accept
|
|
7
|
+
# Execute a system command (use with care)
|
|
8
|
+
def self.exec(command, timeout=10, maxbytes=500)
|
|
9
|
+
output = []
|
|
10
|
+
pro = nil
|
|
11
|
+
begin
|
|
12
|
+
Timeout::timeout(timeout) do
|
|
13
|
+
pro = IO.popen(command)
|
|
14
|
+
until(pro.closed? || pro.eof?)
|
|
15
|
+
if(RUBY_VERSION >= '1.9.0')
|
|
16
|
+
output << pro.getc
|
|
17
|
+
else
|
|
18
|
+
output << pro.getc.chr
|
|
19
|
+
end
|
|
20
|
+
raise IOError.new("Maximum allowed output bytes exceeded. (#{maxbytes} bytes)") unless output.size <= maxbytes
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
output = output.join('')
|
|
24
|
+
rescue Exception => boom
|
|
25
|
+
raise boom
|
|
26
|
+
ensure
|
|
27
|
+
if(RUBY_PLATFORM == 'java')
|
|
28
|
+
Process.kill('KILL', pro.pid) unless pro.nil?
|
|
29
|
+
else
|
|
30
|
+
Process.kill('KILL', pro.pid) if Process.waitpid2(pro.pid, Process::WNOHANG).nil? # make sure the process is dead
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
return output
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Splib
|
|
2
|
+
# IdealHumanRandomIterator - select "random" members of a population, favoring
|
|
3
|
+
# those least-recently selected, to appease silly humans who hate repeats
|
|
4
|
+
#
|
|
5
|
+
# Abstract:
|
|
6
|
+
# given a decently-sized set of items (say, 100 famous quotes), an
|
|
7
|
+
# average persons's idea of N "random" entries is not actually random.
|
|
8
|
+
# people don't want items to appear twice in a row, or too frequently
|
|
9
|
+
# (even though true randomness means this is just as likely as any other order).
|
|
10
|
+
#
|
|
11
|
+
# instead, design a scheme whereby LRU items are weighted more heavily,
|
|
12
|
+
# to "encourage" subsequent selections to not repeat.
|
|
13
|
+
#
|
|
14
|
+
# Author: Ryan "pizza_" Flynn
|
|
15
|
+
# - pulled from the algodict project
|
|
16
|
+
# - - http://github.com/pizza/algodict
|
|
17
|
+
class IdealHumanRandomIterator
|
|
18
|
+
|
|
19
|
+
def initialize(list)
|
|
20
|
+
raise ArgumentError.new("Array type required") unless list.is_a?(Array)
|
|
21
|
+
@items = list
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Given length L, generate a random number in the range [0,len-1), heavily
|
|
25
|
+
# weighted towards the low end.
|
|
26
|
+
def self.nexti(len)
|
|
27
|
+
len += 1 if len % 2 == 1
|
|
28
|
+
index = len > 2 ? rand(len/2) : 0
|
|
29
|
+
return index
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# return a psuedo-random member of items. subsequent calls should never
|
|
33
|
+
# return the same item.
|
|
34
|
+
def next()
|
|
35
|
+
index = IdealHumanRandomIterator.nexti(@items.length)
|
|
36
|
+
@items.push @items.delete_at(index)
|
|
37
|
+
return @items.last
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Splib
|
|
2
|
+
# Exception raised when queue is empty
|
|
3
|
+
class EmptyQueue < Exception
|
|
4
|
+
end
|
|
5
|
+
# This class provides some simple logic for item output. It is
|
|
6
|
+
# basically a priority based queue with some round robin thrown
|
|
7
|
+
# in to keep things interesting. This queue provides an easy way
|
|
8
|
+
# for many threads to populate it without drowning out each other.
|
|
9
|
+
# NOTE: Design help from the great Ryan "pizza_" Flynn
|
|
10
|
+
class PriorityQueue
|
|
11
|
+
|
|
12
|
+
# args:: config arguments
|
|
13
|
+
# :raise_on_empty
|
|
14
|
+
# whocares:: lambda{|target| true||false}
|
|
15
|
+
# Create a priority queue
|
|
16
|
+
def initialize(*args, &whocares)
|
|
17
|
+
@raise = args.include?(:raise_on_empty)
|
|
18
|
+
@whocares = whocares
|
|
19
|
+
@target_queues = {}
|
|
20
|
+
@queues = {:PRIORITY => [], :NEW => [], :NORMAL => [], :WHOCARES => []}
|
|
21
|
+
@lock = Mutex.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# target:: target queue
|
|
25
|
+
# item:: item to queue
|
|
26
|
+
# This prioritizes output to help reduce lag when lots of output
|
|
27
|
+
# is being sent to another target. This will automatically decide
|
|
28
|
+
# how to queue the item based on the target
|
|
29
|
+
def prioritized_queue(target, item)
|
|
30
|
+
raise NameError.new('The target :internal_prio is a restricted target') if target == :internal_prio
|
|
31
|
+
@lock.synchronize do
|
|
32
|
+
@target_queues[target] = [] unless @target_queues[target]
|
|
33
|
+
if(@whocares && @whocares.call(target))
|
|
34
|
+
@target_queues[target] << item
|
|
35
|
+
add_queue(:WHOCARES, @target_queues[target])
|
|
36
|
+
else
|
|
37
|
+
@target_queues[target] << item
|
|
38
|
+
if(@target_queues[target].size < 2)
|
|
39
|
+
add_queue(:NEW, @target_queues[target])
|
|
40
|
+
else
|
|
41
|
+
add_queue(:NORMAL, @target_queues[target])
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
item
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# item:: item to queue
|
|
49
|
+
# This will add item to the PRIORITY queue which gets
|
|
50
|
+
# sent before all other items.
|
|
51
|
+
def direct_queue(message)
|
|
52
|
+
@lock.synchronize do
|
|
53
|
+
@target_queues[:internal_prio] = [] unless @target_queues[:internal_prio]
|
|
54
|
+
@target_queues[:internal_prio] << message
|
|
55
|
+
add_queue(:PRIORITY, @target_queues[:internal_prio])
|
|
56
|
+
end
|
|
57
|
+
message
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# raise_e:: raise an exception on empty
|
|
61
|
+
# Returns the next message to send. This method decides what
|
|
62
|
+
# message to send based on the priority of the message. It
|
|
63
|
+
# will throw an Exceptions::EmptyQueue when there are no messages
|
|
64
|
+
# left.
|
|
65
|
+
def pop
|
|
66
|
+
m = nil
|
|
67
|
+
@lock.synchronize do
|
|
68
|
+
[:PRIORITY, :NEW, :NORMAL, :WHOCARES].each do |k|
|
|
69
|
+
unless(@queues[k].empty?)
|
|
70
|
+
q = @queues[k].shift
|
|
71
|
+
unless(q.empty?)
|
|
72
|
+
m = q.shift
|
|
73
|
+
add_queue(k, q) unless(q.empty?)
|
|
74
|
+
break
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
raise EmptyQueue.new('Queue is currently empty') if m.nil? && @raise
|
|
80
|
+
return m
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Returns true if queue is empty
|
|
84
|
+
def empty?
|
|
85
|
+
@lock.synchronize{@target_queues.values.find{|n|!n.empty?}.nil?}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
alias :push :prioritized_queue
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def add_queue(name, queue)
|
|
93
|
+
unless(@queues[name].include?(queue))
|
|
94
|
+
@queues[name] << queue
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
|
|
3
|
+
module Splib
|
|
4
|
+
# url:: URL to shorten
|
|
5
|
+
# Gets a tinyurl for given URL
|
|
6
|
+
def self.tiny_url(url)
|
|
7
|
+
connection = Net::HTTP.new('tinyurl.com', 80)
|
|
8
|
+
resp, data = connection.get("/api-create.php?url=#{url}")
|
|
9
|
+
if(resp.code !~ /^200$/)
|
|
10
|
+
raise "Failed to make the URL small."
|
|
11
|
+
end
|
|
12
|
+
return data.strip
|
|
13
|
+
end
|
|
14
|
+
# url:: URL to shorten
|
|
15
|
+
# Gets a tr.im for given URL
|
|
16
|
+
def self.trim_url(url)
|
|
17
|
+
connection = Net::HTTP.new('api.tr.im', 80)
|
|
18
|
+
resp, data = connection.get("/v1/trim_simple?url=#{url}")
|
|
19
|
+
if(resp.code !~ /^200$/)
|
|
20
|
+
raise "Failed to make the URL small."
|
|
21
|
+
end
|
|
22
|
+
return data.strip
|
|
23
|
+
end
|
|
24
|
+
# url:: URL to shorten
|
|
25
|
+
# Gets a is.gd for given URL
|
|
26
|
+
def self.isgd_url(url)
|
|
27
|
+
connection = Net::HTTP.new('is.gd', 80)
|
|
28
|
+
resp, data = connection.get("/api.php?longurl=#{url}")
|
|
29
|
+
if(resp.code !~ /^200$/)
|
|
30
|
+
raise "Failed to make the URL small."
|
|
31
|
+
end
|
|
32
|
+
return data.strip
|
|
33
|
+
end
|
|
34
|
+
# url:: URL to shorten
|
|
35
|
+
# Get shortest for given url
|
|
36
|
+
def self.shortest_url(url)
|
|
37
|
+
results = []
|
|
38
|
+
[:tiny_url, :isgd_url, :trim_url].each do |service|
|
|
39
|
+
begin
|
|
40
|
+
results << self.send(service, url)
|
|
41
|
+
rescue
|
|
42
|
+
#ignore#
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
raise 'Failed to make URL small' if results.empty?
|
|
46
|
+
results.sort{|a,b| a.length <=> b.length}[0]
|
|
47
|
+
end
|
|
48
|
+
end
|
data/splib.gemspec
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
spec = Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'splib'
|
|
3
|
+
s.author = 'spox'
|
|
4
|
+
s.email = 'spox@modspox.com'
|
|
5
|
+
s.version = '1.0'
|
|
6
|
+
s.summary = 'Spox Library'
|
|
7
|
+
s.platform = Gem::Platform::RUBY
|
|
8
|
+
s.files = Dir['**/*']
|
|
9
|
+
s.rdoc_options = %w(--title splib --main README.rdoc --line-numbers)
|
|
10
|
+
s.extra_rdoc_files = %w(README.rdoc CHANGELOG)
|
|
11
|
+
s.require_paths = %w(lib)
|
|
12
|
+
s.required_ruby_version = '>= 1.8.6'
|
|
13
|
+
s.homepage = %q(http://github.com/spox/splib)
|
|
14
|
+
s.description = "The spox library contains various useful tools to help you in your day to day life. Like a trusty pocket knife, only more computery."
|
|
15
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
class CodeReloaderTest < Test::Unit::TestCase
|
|
6
|
+
def setup
|
|
7
|
+
@s = File.expand_path("#{__FILE__}/../../samplecode.rb")
|
|
8
|
+
@s1 = File.expand_path("#{__FILE__}/../../samplecode1.rb")
|
|
9
|
+
@s2 = File.expand_path("#{__FILE__}/../../samplecode2.rb")
|
|
10
|
+
Splib.load :CodeReloader
|
|
11
|
+
Splib.load :Constants
|
|
12
|
+
FileUtils.cp @s1, @s
|
|
13
|
+
end
|
|
14
|
+
def teardown
|
|
15
|
+
FileUtils.rm @s, :force => true
|
|
16
|
+
end
|
|
17
|
+
def test_load
|
|
18
|
+
holder = Splib.load_code(@s)
|
|
19
|
+
klass = Splib.find_const('Fu::Bar', [holder])
|
|
20
|
+
obj = klass.new
|
|
21
|
+
assert_equal('hello world', obj.foobar)
|
|
22
|
+
end
|
|
23
|
+
def test_reload
|
|
24
|
+
holder = Splib.load_code(@s)
|
|
25
|
+
klass = Splib.find_const('Fu::Bar', [holder])
|
|
26
|
+
obj = klass.new
|
|
27
|
+
assert(obj.respond_to?(:foobar))
|
|
28
|
+
assert(!obj.respond_to?(:feebar))
|
|
29
|
+
assert_equal('hello world', obj.foobar)
|
|
30
|
+
FileUtils.cp @s2, @s
|
|
31
|
+
Splib.reload_code(holder)
|
|
32
|
+
klass = Splib.find_const('Fu::Bar', [holder])
|
|
33
|
+
obj = klass.new
|
|
34
|
+
assert(obj.respond_to?(:feebar))
|
|
35
|
+
assert(!obj.respond_to?(:foobar))
|
|
36
|
+
assert_equal('goodbye world', obj.feebar)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
module Foo
|
|
5
|
+
module Bar
|
|
6
|
+
class Fubar
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class ConstantsTest < Test::Unit::TestCase
|
|
12
|
+
def setup
|
|
13
|
+
Splib.load :Constants
|
|
14
|
+
end
|
|
15
|
+
def test_find_const
|
|
16
|
+
mod = Module.new
|
|
17
|
+
mod.class_eval("
|
|
18
|
+
module Fu
|
|
19
|
+
class Bar
|
|
20
|
+
end
|
|
21
|
+
end"
|
|
22
|
+
)
|
|
23
|
+
assert_equal(String, Splib.find_const('String'))
|
|
24
|
+
assert_equal(Foo::Bar::Fubar, Splib.find_const('Foo::Bar::Fubar'))
|
|
25
|
+
assert_match(/<.+?>::Fu::Bar/, Splib.find_const('Fu::Bar', [mod]).to_s)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class ConversionsTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
Splib.load :Conversions
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_format_seconds
|
|
10
|
+
inc = {:year => 60 * 60 * 24 * 365,
|
|
11
|
+
:month => 60 * 60 * 24 * 31,
|
|
12
|
+
:week => 60 * 60 * 24 * 7,
|
|
13
|
+
:day => 60 * 60 * 24,
|
|
14
|
+
:hour => 60 * 60,
|
|
15
|
+
:minute => 60,
|
|
16
|
+
:second => 1}
|
|
17
|
+
100.times do |i|
|
|
18
|
+
time = rand(i)
|
|
19
|
+
otime = time
|
|
20
|
+
formatted = []
|
|
21
|
+
inc.each_pair do |name, value|
|
|
22
|
+
val = (time / value).to_i
|
|
23
|
+
if(val > 0)
|
|
24
|
+
time = time - (val * value)
|
|
25
|
+
formatted << "#{val} #{val == 1 ? name : "#{name}s"}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
formatted = formatted.empty? ? '0 seconds' : formatted.join(' ')
|
|
29
|
+
assert_equal(Splib.format_seconds(otime), formatted)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_format_size
|
|
34
|
+
inc = {"byte" => 1024**0, # 1024^0
|
|
35
|
+
"Kilobyte" => 1024**1, # 1024^1
|
|
36
|
+
"Megabyte" => 1024**2, # 1024^2
|
|
37
|
+
"Gigabyte" => 1024**3, # 1024^3
|
|
38
|
+
"Terabyte" => 1024**4, # 1024^4
|
|
39
|
+
"Petabyte" => 1024**5, # 1024^5
|
|
40
|
+
"Exabyte" => 1024**6, # 1024^6
|
|
41
|
+
"Zettabyte" => 1024**7, # 1024^7
|
|
42
|
+
"Yottabyte" => 1024**8 # 1024^8
|
|
43
|
+
}
|
|
44
|
+
100.times do |i|
|
|
45
|
+
val = i**rand(i)
|
|
46
|
+
formatted = nil
|
|
47
|
+
inc.each_pair do |name, value|
|
|
48
|
+
v = val / value.to_f
|
|
49
|
+
if(v.to_i > 0)
|
|
50
|
+
formatted = ("%.2f " % v) + " #{name}#{v == 1 ? '' : 's'}".strip
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
formatted = '0 bytes' if formatted.nil?
|
|
54
|
+
assert_equal(formatted, Splib.format_size(val))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/tests/cases/Exec.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class ExecTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
Splib.load :Exec
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_exec
|
|
10
|
+
assert_raise(IOError) do
|
|
11
|
+
Splib.exec('echo test', 10, 1)
|
|
12
|
+
end
|
|
13
|
+
assert_raise(Timeout::Error) do
|
|
14
|
+
Splib.exec('while [ true ]; do true; done;', 1)
|
|
15
|
+
end
|
|
16
|
+
assert_equal("test\n", Splib.exec('echo test'))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class HumanIdealRandomIteratorTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
Splib.load :HumanIdealRandomIterator
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_iterator
|
|
10
|
+
assert_raise(EOFError) do
|
|
11
|
+
100.times do
|
|
12
|
+
results = []
|
|
13
|
+
pool = (0..rand(1000)).to_a
|
|
14
|
+
ideal = Splib::IdealHumanRandomIterator.new(pool)
|
|
15
|
+
(pool.size / 2).times do
|
|
16
|
+
n = ideal.next()
|
|
17
|
+
if(results.include?(n))
|
|
18
|
+
raise ArgumentError.new("Duplicated result")
|
|
19
|
+
else
|
|
20
|
+
results << n
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
raise EOFError.new("OK")
|
|
25
|
+
end
|
|
26
|
+
assert_raise(ArgumentError){ Splib::IdealHumanRandomIterator.new(1) }
|
|
27
|
+
assert_nil(Splib::IdealHumanRandomIterator.new([]).next)
|
|
28
|
+
assert_equal(0, Splib::IdealHumanRandomIterator.new([0]).next)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class PriorityQueueTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
Splib.load :PriorityQueue
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_direct
|
|
10
|
+
queue = Splib::PriorityQueue.new
|
|
11
|
+
queue.direct_queue(1)
|
|
12
|
+
assert_equal(1, queue.pop)
|
|
13
|
+
queue.direct_queue(2)
|
|
14
|
+
queue.direct_queue(3)
|
|
15
|
+
assert_equal(2, queue.pop)
|
|
16
|
+
assert_equal(3, queue.pop)
|
|
17
|
+
assert(queue.empty?)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_prioritizer
|
|
21
|
+
queue = Splib::PriorityQueue.new
|
|
22
|
+
5.times{queue.push('slot1', 'test')}
|
|
23
|
+
5.times{queue.push('slot2', 'fubar')}
|
|
24
|
+
queue.direct_queue('first')
|
|
25
|
+
assert_equal('first', queue.pop)
|
|
26
|
+
5.times do
|
|
27
|
+
assert_equal('test', queue.pop)
|
|
28
|
+
assert_equal('fubar', queue.pop)
|
|
29
|
+
end
|
|
30
|
+
assert(queue.empty?)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_whocares
|
|
34
|
+
queue = Splib::PriorityQueue.new{|s| s == :last }
|
|
35
|
+
queue.push(:last, 'last')
|
|
36
|
+
2.times{ queue.push(:slot1, 'test') }
|
|
37
|
+
2.times{ queue.push(:slot2, 'fubar') }
|
|
38
|
+
2.times do
|
|
39
|
+
assert_equal('test', queue.pop)
|
|
40
|
+
assert_equal('fubar', queue.pop)
|
|
41
|
+
end
|
|
42
|
+
assert_equal('last', queue.pop)
|
|
43
|
+
assert(queue.empty?)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'splib'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class UrlShortenersTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
Splib.load :UrlShorteners
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_tiny_url
|
|
10
|
+
assert_match(/^http:\/\/[\w|\.|\/]+$/, Splib.tiny_url('www.google.com'))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_trim_url
|
|
14
|
+
assert_match(/^http:\/\/[\w|\.|\/]+$/, Splib.trim_url('www.google.com'))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_isgd_url
|
|
18
|
+
assert_match(/^http:\/\/[\w|\.|\/]+$/, Splib.isgd_url('www.google.com'))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_shortest_url
|
|
22
|
+
assert_match(/^http:\/\/[\w|\.|\/]+$/, Splib.shortest_url('www.google.com'))
|
|
23
|
+
end
|
|
24
|
+
end
|
data/tests/run_tests.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: splib
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: "1.0"
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- spox
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-12-17 00:00:00 -08:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description: The spox library contains various useful tools to help you in your day to day life. Like a trusty pocket knife, only more computery.
|
|
17
|
+
email: spox@modspox.com
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions: []
|
|
21
|
+
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- README.rdoc
|
|
24
|
+
- CHANGELOG
|
|
25
|
+
files:
|
|
26
|
+
- tests/cases/PriorityQueue.rb
|
|
27
|
+
- tests/cases/UrlShorteners.rb
|
|
28
|
+
- tests/cases/Exec.rb
|
|
29
|
+
- tests/cases/Constants.rb
|
|
30
|
+
- tests/cases/CodeReloader.rb
|
|
31
|
+
- tests/cases/HumanIdealRandomIterator.rb
|
|
32
|
+
- tests/cases/Conversions.rb
|
|
33
|
+
- tests/run_tests.rb
|
|
34
|
+
- tests/samplecode2.rb
|
|
35
|
+
- tests/samplecode1.rb
|
|
36
|
+
- lib/splib.rb
|
|
37
|
+
- lib/splib/PriorityQueue.rb
|
|
38
|
+
- lib/splib/UrlShorteners.rb
|
|
39
|
+
- lib/splib/Exec.rb
|
|
40
|
+
- lib/splib/Constants.rb
|
|
41
|
+
- lib/splib/CodeReloader.rb
|
|
42
|
+
- lib/splib/HumanIdealRandomIterator.rb
|
|
43
|
+
- lib/splib/Conversions.rb
|
|
44
|
+
- CHANGELOG
|
|
45
|
+
- LICENSE
|
|
46
|
+
- splib.gemspec
|
|
47
|
+
- README.rdoc
|
|
48
|
+
has_rdoc: true
|
|
49
|
+
homepage: http://github.com/spox/splib
|
|
50
|
+
licenses: []
|
|
51
|
+
|
|
52
|
+
post_install_message:
|
|
53
|
+
rdoc_options:
|
|
54
|
+
- --title
|
|
55
|
+
- splib
|
|
56
|
+
- --main
|
|
57
|
+
- README.rdoc
|
|
58
|
+
- --line-numbers
|
|
59
|
+
require_paths:
|
|
60
|
+
- lib
|
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: 1.8.6
|
|
66
|
+
version:
|
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: "0"
|
|
72
|
+
version:
|
|
73
|
+
requirements: []
|
|
74
|
+
|
|
75
|
+
rubyforge_project:
|
|
76
|
+
rubygems_version: 1.3.5
|
|
77
|
+
signing_key:
|
|
78
|
+
specification_version: 3
|
|
79
|
+
summary: Spox Library
|
|
80
|
+
test_files: []
|
|
81
|
+
|