buzzcorej 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +63 -0
- data/VERSION +2 -0
- data/buzzcorej.gemspec +58 -0
- data/buzzcorej.vpj +93 -0
- data/buzzcorej.vpw +93 -0
- data/lib/buzzcorej/enum.rb +50 -0
- data/lib/buzzcorej/extend_base_classes.rb +485 -0
- data/lib/buzzcorej/misc_utils.rb +334 -0
- data/lib/buzzcorej/require_paths.rb +39 -0
- data/lib/buzzcorej/string_utils.rb +95 -0
- data/lib/buzzcorej_dev.rb +6 -0
- metadata +15 -4
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "buzzcorej"
|
8
|
+
gem.summary = %Q{buzzcorej is the JRuby core library developed and used by Buzzware Solutions.}
|
9
|
+
gem.description = %Q{buzzcorej is the JRuby core library developed and used by Buzzware Solutions.}
|
10
|
+
gem.email = "contact@buzzware.com.au"
|
11
|
+
gem.homepage = "http://github.com/buzzware/buzzcorej"
|
12
|
+
gem.authors = ["buzzware"]
|
13
|
+
gem.add_development_dependency "shoulda"
|
14
|
+
gem.files.include %w(
|
15
|
+
lib/buzzcorej.rb
|
16
|
+
)
|
17
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
+
end
|
19
|
+
Jeweler::GemcutterTasks.new
|
20
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
21
|
+
rubyforge.doc_task = "rdoc"
|
22
|
+
end
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/*_test.rb'
|
39
|
+
test.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :test => :check_dependencies
|
48
|
+
|
49
|
+
task :default => :test
|
50
|
+
|
51
|
+
require 'rake/rdoctask'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
if File.exist?('VERSION')
|
54
|
+
version = File.read('VERSION')
|
55
|
+
else
|
56
|
+
version = ""
|
57
|
+
end
|
58
|
+
|
59
|
+
rdoc.rdoc_dir = 'rdoc'
|
60
|
+
rdoc.title = "buzzcorej #{version}"
|
61
|
+
rdoc.rdoc_files.include('README*')
|
62
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
63
|
+
end
|
data/VERSION
ADDED
data/buzzcorej.gemspec
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{buzzcorej}
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["buzzware"]
|
12
|
+
s.date = %q{2010-08-15}
|
13
|
+
s.description = %q{buzzcorej is the JRuby core library developed and used by Buzzware Solutions.}
|
14
|
+
s.email = %q{contact@buzzware.com.au}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"buzzcorej.gemspec",
|
25
|
+
"buzzcorej.vpj",
|
26
|
+
"buzzcorej.vpw",
|
27
|
+
"lib/buzzcorej.rb",
|
28
|
+
"lib/buzzcorej/enum.rb",
|
29
|
+
"lib/buzzcorej/extend_base_classes.rb",
|
30
|
+
"lib/buzzcorej/misc_utils.rb",
|
31
|
+
"lib/buzzcorej/require_paths.rb",
|
32
|
+
"lib/buzzcorej/string_utils.rb",
|
33
|
+
"lib/buzzcorej_dev.rb",
|
34
|
+
"test/test_helper.rb"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/buzzware/buzzcorej}
|
37
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.7}
|
40
|
+
s.summary = %q{buzzcorej is the JRuby core library developed and used by Buzzware Solutions.}
|
41
|
+
s.test_files = [
|
42
|
+
"test/test_helper.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
data/buzzcorej.vpj
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
|
2
|
+
<Project
|
3
|
+
Version="10.0"
|
4
|
+
VendorName="SlickEdit"
|
5
|
+
WorkingDir=".">
|
6
|
+
<Config
|
7
|
+
Name="Release"
|
8
|
+
OutputFile=""
|
9
|
+
CompilerConfigName="Latest Version">
|
10
|
+
<Menu>
|
11
|
+
<Target
|
12
|
+
Name="Compile"
|
13
|
+
MenuCaption="&Compile"
|
14
|
+
CaptureOutputWith="ProcessBuffer"
|
15
|
+
SaveOption="SaveCurrent"
|
16
|
+
RunFromDir="%rw">
|
17
|
+
<Exec/>
|
18
|
+
</Target>
|
19
|
+
<Target
|
20
|
+
Name="Build"
|
21
|
+
MenuCaption="&Build"
|
22
|
+
CaptureOutputWith="ProcessBuffer"
|
23
|
+
SaveOption="SaveWorkspaceFiles"
|
24
|
+
RunFromDir="%rw">
|
25
|
+
<Exec/>
|
26
|
+
</Target>
|
27
|
+
<Target
|
28
|
+
Name="Rebuild"
|
29
|
+
MenuCaption="&Rebuild"
|
30
|
+
CaptureOutputWith="ProcessBuffer"
|
31
|
+
SaveOption="SaveWorkspaceFiles"
|
32
|
+
RunFromDir="%rw">
|
33
|
+
<Exec/>
|
34
|
+
</Target>
|
35
|
+
<Target
|
36
|
+
Name="Debug"
|
37
|
+
MenuCaption="&Debug"
|
38
|
+
SaveOption="SaveNone"
|
39
|
+
RunFromDir="%rw">
|
40
|
+
<Exec/>
|
41
|
+
</Target>
|
42
|
+
<Target
|
43
|
+
Name="Execute"
|
44
|
+
MenuCaption="E&xecute"
|
45
|
+
SaveOption="SaveNone"
|
46
|
+
RunFromDir="%rw"
|
47
|
+
CaptureOutputWith="ProcessBuffer"
|
48
|
+
ClearProcessBuffer="1">
|
49
|
+
<Exec CmdLine="source actions.sh execute"/>
|
50
|
+
</Target>
|
51
|
+
</Menu>
|
52
|
+
</Config>
|
53
|
+
<CustomFolders>
|
54
|
+
<Folder
|
55
|
+
Name="Source Files"
|
56
|
+
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl"/>
|
57
|
+
<Folder
|
58
|
+
Name="Header Files"
|
59
|
+
Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if"/>
|
60
|
+
<Folder
|
61
|
+
Name="Resource Files"
|
62
|
+
Filters="*.ico;*.cur;*.dlg"/>
|
63
|
+
<Folder
|
64
|
+
Name="Bitmaps"
|
65
|
+
Filters="*.bmp"/>
|
66
|
+
<Folder
|
67
|
+
Name="Other Files"
|
68
|
+
Filters="">
|
69
|
+
</Folder>
|
70
|
+
</CustomFolders>
|
71
|
+
<Files AutoFolders="DirectoryView">
|
72
|
+
<Folder Name="lib">
|
73
|
+
<F
|
74
|
+
N="lib/*"
|
75
|
+
Recurse="1"
|
76
|
+
Refilter="0"
|
77
|
+
Excludes=""/>
|
78
|
+
</Folder>
|
79
|
+
<Folder Name="test">
|
80
|
+
<F
|
81
|
+
N="test/*"
|
82
|
+
Recurse="0"
|
83
|
+
Refilter="0"
|
84
|
+
Excludes=".svn/"/>
|
85
|
+
</Folder>
|
86
|
+
<F N="buzzcorej.gemspec"/>
|
87
|
+
<F N="History.txt"/>
|
88
|
+
<F N="Manifest.txt"/>
|
89
|
+
<F N="PostInstall.txt"/>
|
90
|
+
<F N="Rakefile"/>
|
91
|
+
<F N="README.rdoc"/>
|
92
|
+
</Files>
|
93
|
+
</Project>
|
data/buzzcorej.vpw
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
|
2
|
+
<Project
|
3
|
+
Version="10.0"
|
4
|
+
VendorName="SlickEdit"
|
5
|
+
WorkingDir=".">
|
6
|
+
<Config
|
7
|
+
Name="Release"
|
8
|
+
OutputFile=""
|
9
|
+
CompilerConfigName="Latest Version">
|
10
|
+
<Menu>
|
11
|
+
<Target
|
12
|
+
Name="Compile"
|
13
|
+
MenuCaption="&Compile"
|
14
|
+
CaptureOutputWith="ProcessBuffer"
|
15
|
+
SaveOption="SaveCurrent"
|
16
|
+
RunFromDir="%rw">
|
17
|
+
<Exec/>
|
18
|
+
</Target>
|
19
|
+
<Target
|
20
|
+
Name="Build"
|
21
|
+
MenuCaption="&Build"
|
22
|
+
CaptureOutputWith="ProcessBuffer"
|
23
|
+
SaveOption="SaveWorkspaceFiles"
|
24
|
+
RunFromDir="%rw">
|
25
|
+
<Exec/>
|
26
|
+
</Target>
|
27
|
+
<Target
|
28
|
+
Name="Rebuild"
|
29
|
+
MenuCaption="&Rebuild"
|
30
|
+
CaptureOutputWith="ProcessBuffer"
|
31
|
+
SaveOption="SaveWorkspaceFiles"
|
32
|
+
RunFromDir="%rw">
|
33
|
+
<Exec/>
|
34
|
+
</Target>
|
35
|
+
<Target
|
36
|
+
Name="Debug"
|
37
|
+
MenuCaption="&Debug"
|
38
|
+
SaveOption="SaveNone"
|
39
|
+
RunFromDir="%rw">
|
40
|
+
<Exec/>
|
41
|
+
</Target>
|
42
|
+
<Target
|
43
|
+
Name="Execute"
|
44
|
+
MenuCaption="E&xecute"
|
45
|
+
SaveOption="SaveNone"
|
46
|
+
RunFromDir="%rw"
|
47
|
+
CaptureOutputWith="ProcessBuffer"
|
48
|
+
ClearProcessBuffer="1">
|
49
|
+
<Exec CmdLine="source actions.sh execute"/>
|
50
|
+
</Target>
|
51
|
+
</Menu>
|
52
|
+
</Config>
|
53
|
+
<CustomFolders>
|
54
|
+
<Folder
|
55
|
+
Name="Source Files"
|
56
|
+
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl"/>
|
57
|
+
<Folder
|
58
|
+
Name="Header Files"
|
59
|
+
Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if"/>
|
60
|
+
<Folder
|
61
|
+
Name="Resource Files"
|
62
|
+
Filters="*.ico;*.cur;*.dlg"/>
|
63
|
+
<Folder
|
64
|
+
Name="Bitmaps"
|
65
|
+
Filters="*.bmp"/>
|
66
|
+
<Folder
|
67
|
+
Name="Other Files"
|
68
|
+
Filters="">
|
69
|
+
</Folder>
|
70
|
+
</CustomFolders>
|
71
|
+
<Files AutoFolders="DirectoryView">
|
72
|
+
<Folder Name="lib">
|
73
|
+
<F
|
74
|
+
N="lib/*"
|
75
|
+
Recurse="1"
|
76
|
+
Refilter="0"
|
77
|
+
Excludes=""/>
|
78
|
+
</Folder>
|
79
|
+
<Folder Name="test">
|
80
|
+
<F
|
81
|
+
N="test/*"
|
82
|
+
Recurse="0"
|
83
|
+
Refilter="0"
|
84
|
+
Excludes=".svn/"/>
|
85
|
+
</Folder>
|
86
|
+
<F N="buzzcorej.gemspec"/>
|
87
|
+
<F N="History.txt"/>
|
88
|
+
<F N="Manifest.txt"/>
|
89
|
+
<F N="PostInstall.txt"/>
|
90
|
+
<F N="Rakefile"/>
|
91
|
+
<F N="README.rdoc"/>
|
92
|
+
</Files>
|
93
|
+
</Project>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Kernel
|
2
|
+
# simple (sequential) enumerated values
|
3
|
+
# usage :
|
4
|
+
#
|
5
|
+
# module Constants
|
6
|
+
# module Gradient
|
7
|
+
# enum :B, :A, :C
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# then :
|
12
|
+
#
|
13
|
+
# puts Constants::Gradient::B -> 0
|
14
|
+
# puts Constants::Gradient::C -> 2
|
15
|
+
# puts Constants::Gradient::MINVALUE -> 0
|
16
|
+
# puts Constants::Gradient::MAXVALUE -> 2
|
17
|
+
# puts Constants::Gradient::NAMES -> [:B, :A, :C]
|
18
|
+
# puts Constants::Gradient[0] -> :B
|
19
|
+
# puts Constants::Gradient[1] -> :A
|
20
|
+
# puts Constants::Gradient[2] -> :C
|
21
|
+
|
22
|
+
def enum(*syms)
|
23
|
+
syms.each_index { |i|
|
24
|
+
const_set(syms[i], i)
|
25
|
+
}
|
26
|
+
const_set(:NAMES, syms || [])
|
27
|
+
const_set(:MINVALUE, syms==nil ? nil : 0)
|
28
|
+
const_set(:MAXVALUE, syms==nil ? nil : syms.length-1)
|
29
|
+
const_set(:VALUECOUNT, syms==nil ? nil : syms.length)
|
30
|
+
const_set(:ALL, syms==nil ? [] : (0..syms.length-1).to_a)
|
31
|
+
const_set(:HUMAN_NAMES, syms.map{|n| n.to_s.humanize} || [])
|
32
|
+
|
33
|
+
# this returns the enum name given the value
|
34
|
+
def self.[]( idx )
|
35
|
+
(idx.is_a? Integer) ? const_get(:NAMES)[idx] : nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.valid?(idx)
|
39
|
+
(idx.is_a? Integer) && (idx >= 0) && (idx <= const_get(:MAXVALUE))
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.parse(name,default=nil)
|
43
|
+
return default if name.nil? || name.empty?
|
44
|
+
return default if not name = name.to_sym
|
45
|
+
result = const_get(:NAMES).index(name)
|
46
|
+
return result==nil ? default : result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,485 @@
|
|
1
|
+
String.class_eval do
|
2
|
+
def pad_left(value)
|
3
|
+
increase = value-self.length
|
4
|
+
return self if increase==0
|
5
|
+
if increase > 0
|
6
|
+
return self + ' '*increase
|
7
|
+
else
|
8
|
+
return self[0,value]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def pad_right(value)
|
13
|
+
increase = value-self.length
|
14
|
+
return self if increase==0
|
15
|
+
if increase > 0
|
16
|
+
return ' '*increase + self
|
17
|
+
else
|
18
|
+
return self[0,value]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Like chomp! but operates on the leading characters instead.
|
23
|
+
# The aString parameter would not normally be used.
|
24
|
+
def bite!(aValue=$/,aString=self)
|
25
|
+
if aString[0,aValue.length] == aValue
|
26
|
+
aString[0,aValue.length] = ''
|
27
|
+
return aString
|
28
|
+
else
|
29
|
+
return aString
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def bite(aValue=$/)
|
34
|
+
bite!(aValue,self.clone)
|
35
|
+
end
|
36
|
+
|
37
|
+
def begins_with?(aString)
|
38
|
+
self[0,aString.length]==aString
|
39
|
+
end
|
40
|
+
|
41
|
+
def ends_with?(aString)
|
42
|
+
self[-aString.length,aString.length]==aString
|
43
|
+
end
|
44
|
+
|
45
|
+
# for future methods
|
46
|
+
# def centre_bar(aChar = '-', indent = 6)
|
47
|
+
# (' '*indent) + aChar*(@width-(indent*2)) + (' '*indent)
|
48
|
+
# end
|
49
|
+
# def replace_string(aString,aCol,aSubString)
|
50
|
+
# return aString if aSubString==nil || aSubString==''
|
51
|
+
#
|
52
|
+
# aSubString = aSubString.to_s
|
53
|
+
# start_col = aCol < 0 ? 0 : aCol
|
54
|
+
# end_col = aCol+aSubString.length-1
|
55
|
+
# end_col = @width-1 if end_col >= @width
|
56
|
+
# source_len = end_col-start_col+1
|
57
|
+
# return aString if source_len <= 0 || end_col < 0 || start_col >= @width
|
58
|
+
# aString += ' '*((end_col+1) - aString.length) if aString.length < end_col+1
|
59
|
+
# aString[start_col,source_len] = aSubString[start_col-aCol,end_col-start_col+1]
|
60
|
+
# return aString
|
61
|
+
# end
|
62
|
+
|
63
|
+
def to_integer(aDefault=nil)
|
64
|
+
t = self.strip
|
65
|
+
return aDefault if t.empty? || !t.index(/^-{0,1}[0-9]+$/)
|
66
|
+
return t.to_i
|
67
|
+
end
|
68
|
+
|
69
|
+
def is_i?
|
70
|
+
self.to_integer(false) and true
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_float(aDefault=nil)
|
74
|
+
t = self.strip
|
75
|
+
return aDefault if !t =~ /(\+|-)?([0-9]+\.?[0-9]*|\.[0-9]+)([eE](\+|-)?[0-9]+)?/
|
76
|
+
return t.to_f
|
77
|
+
end
|
78
|
+
|
79
|
+
def is_f?
|
80
|
+
self.to_float(false) and true
|
81
|
+
end
|
82
|
+
|
83
|
+
# like scan but returns array of MatchData's.
|
84
|
+
# doesn't yet support blocks
|
85
|
+
def scan_md(aPattern)
|
86
|
+
result = []
|
87
|
+
self.scan(aPattern) {|s| result << $~ }
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_nil(aPattern=nil)
|
92
|
+
return nil if self.empty?
|
93
|
+
if aPattern
|
94
|
+
return nil if (aPattern.is_a? Regexp) && (self =~ aPattern)
|
95
|
+
return nil if aPattern.to_s == self
|
96
|
+
end
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_b(aDefault=false)
|
101
|
+
return true if ['1','yes','y','true','on'].include?(self.downcase)
|
102
|
+
return false if ['0','no','n','false','off'].include?(self.downcase)
|
103
|
+
aDefault
|
104
|
+
end
|
105
|
+
|
106
|
+
# uses
|
107
|
+
#URLIZE_PATTERN = /[ \/\\\(\)\[\]]/
|
108
|
+
URLIZE_PATTERN_PS = /[ \\\(\)\[\]_]/
|
109
|
+
def urlize(aSlashChar='+')
|
110
|
+
return self if self.empty?
|
111
|
+
result = self.gsub(URLIZE_PATTERN_PS,'-').downcase.gsub(/[^a-z0-9_\-+,\.\/]/,'')
|
112
|
+
result.gsub!('/',aSlashChar) unless aSlashChar=='/'
|
113
|
+
result.gsub!(/-{2,}/,'-')
|
114
|
+
result
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
CRC_LOOKUP = [
|
119
|
+
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
120
|
+
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
121
|
+
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
122
|
+
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
123
|
+
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
124
|
+
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
125
|
+
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
126
|
+
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
127
|
+
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
128
|
+
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
129
|
+
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
130
|
+
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
131
|
+
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
132
|
+
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
133
|
+
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
134
|
+
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
135
|
+
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
136
|
+
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
137
|
+
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
138
|
+
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
139
|
+
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
140
|
+
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
141
|
+
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
142
|
+
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
143
|
+
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
144
|
+
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
145
|
+
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
146
|
+
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
147
|
+
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
148
|
+
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
149
|
+
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
150
|
+
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
151
|
+
]
|
152
|
+
public
|
153
|
+
|
154
|
+
def crc16
|
155
|
+
crc = 0x00
|
156
|
+
self.each_byte do |b|
|
157
|
+
crc = ((crc >> 8) & 0xff) ^ CRC_LOOKUP[(crc ^ b) & 0xff]
|
158
|
+
end
|
159
|
+
crc
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
Time.class_eval do
|
167
|
+
|
168
|
+
if !respond_to?(:change) # no activesupport loaded
|
169
|
+
def change(options)
|
170
|
+
::Time.send(
|
171
|
+
self.utc? ? :utc : :local,
|
172
|
+
options[:year] || self.year,
|
173
|
+
options[:month] || self.month,
|
174
|
+
options[:day] || self.day,
|
175
|
+
options[:hour] || self.hour,
|
176
|
+
options[:min] || (options[:hour] ? 0 : self.min),
|
177
|
+
options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
|
178
|
+
options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec)
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
def seconds_since_midnight
|
183
|
+
self.to_i - self.change(:hour => 0).to_i + (self.usec/1.0e+6)
|
184
|
+
end
|
185
|
+
|
186
|
+
def beginning_of_day
|
187
|
+
(self - self.seconds_since_midnight).change(:usec => 0)
|
188
|
+
end
|
189
|
+
|
190
|
+
alias :midnight :beginning_of_day
|
191
|
+
alias :at_midnight :beginning_of_day
|
192
|
+
alias :at_beginning_of_day :beginning_of_day
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
# offset of local machine from UTC, in seconds eg +9.hours
|
197
|
+
def self.local_offset
|
198
|
+
local(2000).utc_offset
|
199
|
+
end
|
200
|
+
|
201
|
+
def date
|
202
|
+
self.at_beginning_of_day
|
203
|
+
end
|
204
|
+
|
205
|
+
# index number of this day, from Time.at(0) + utc_offset
|
206
|
+
def day_number
|
207
|
+
(self.to_i+self.utc_offset) / 86400
|
208
|
+
end
|
209
|
+
|
210
|
+
# index number of this utc day
|
211
|
+
def day_number_utc
|
212
|
+
self.to_i / 86400
|
213
|
+
end
|
214
|
+
|
215
|
+
# the last microsecond of the day
|
216
|
+
def day_end
|
217
|
+
self.at_beginning_of_day + 86399.999999
|
218
|
+
end
|
219
|
+
|
220
|
+
def date_numeric
|
221
|
+
self.strftime('%Y%m%d')
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_universal
|
225
|
+
self.strftime("%d %b %Y")
|
226
|
+
end
|
227
|
+
|
228
|
+
# create a new Time from eg. "20081231"
|
229
|
+
def self.from_date_numeric(aString)
|
230
|
+
return nil unless aString
|
231
|
+
local(aString[0,4].to_i,aString[4,2].to_i,aString[6,2].to_i)
|
232
|
+
end
|
233
|
+
|
234
|
+
def time_numeric
|
235
|
+
self.strftime('%H%M%S')
|
236
|
+
end
|
237
|
+
|
238
|
+
def datetime_numeric
|
239
|
+
self.strftime('%Y%m%d-%H%M%S')
|
240
|
+
end
|
241
|
+
|
242
|
+
def to_sql
|
243
|
+
self.strftime('%Y-%m-%d %H:%M:%S')
|
244
|
+
end
|
245
|
+
|
246
|
+
def to_w3c
|
247
|
+
utc.strftime("%Y-%m-%dT%H:%M:%S+00:00")
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
module HashUtils
|
252
|
+
def filter_include!(aKeys,aHash=nil)
|
253
|
+
aHash ||= self
|
254
|
+
|
255
|
+
if aKeys.is_a? Regexp
|
256
|
+
return aHash.delete_if {|k,v| not k =~ aKeys }
|
257
|
+
else
|
258
|
+
aKeys = [aKeys] unless aKeys.is_a? Array
|
259
|
+
return aHash.clear if aKeys.empty?
|
260
|
+
return aHash.delete_if {|key, value| !((aKeys.include?(key)) || (key.is_a?(Symbol) and aKeys.include?(key.to_s)) || (key.is_a?(String) and aKeys.include?(key.to_sym)))}
|
261
|
+
return aHash # last resort
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def filter_include(aKeys,aHash=nil)
|
266
|
+
aHash ||= self
|
267
|
+
filter_include!(aKeys,aHash.clone)
|
268
|
+
end
|
269
|
+
|
270
|
+
def filter_exclude!(aKeys,aHash=nil)
|
271
|
+
aHash ||= self
|
272
|
+
|
273
|
+
if aKeys.is_a? Regexp
|
274
|
+
return aHash.delete_if {|k,v| k =~ aKeys }
|
275
|
+
else
|
276
|
+
aKeys = [aKeys] unless aKeys.is_a? Array
|
277
|
+
return aHash if aKeys.empty?
|
278
|
+
return aHash.delete_if {|key, value| ((aKeys.include?(key)) || (key.is_a?(Symbol) and aKeys.include?(key.to_s)) || (key.is_a?(String) and aKeys.include?(key.to_sym)))}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def filter_exclude(aKeys,aHash=nil)
|
283
|
+
aHash ||= self
|
284
|
+
filter_exclude!(aKeys,aHash.clone)
|
285
|
+
end
|
286
|
+
|
287
|
+
def has_values_for?(aKeys,aHash=nil)
|
288
|
+
aHash ||= self
|
289
|
+
# check all keys exist in aHash and their values are not nil
|
290
|
+
aKeys.all? { |k,v| aHash[k] }
|
291
|
+
end
|
292
|
+
|
293
|
+
# give a block to execute without the given key in this hash
|
294
|
+
# It will be replaced after the block (guaranteed by ensure)
|
295
|
+
# eg.
|
296
|
+
# hash.without_key(:blah) do |aHash|
|
297
|
+
# puts aHash.inspect
|
298
|
+
# end
|
299
|
+
def without_key(aKey)
|
300
|
+
temp = nil
|
301
|
+
h = self
|
302
|
+
begin
|
303
|
+
if h.include?(aKey)
|
304
|
+
temp = [aKey,h.delete(aKey)]
|
305
|
+
end
|
306
|
+
result = yield(h)
|
307
|
+
ensure
|
308
|
+
h[temp[0]] = temp[1] if temp
|
309
|
+
end
|
310
|
+
return result
|
311
|
+
end
|
312
|
+
|
313
|
+
def symbolize_keys
|
314
|
+
result = {}
|
315
|
+
self.each { |k,v| k.is_a?(String) ? result[k.to_sym] = v : result[k] = v }
|
316
|
+
return result
|
317
|
+
end
|
318
|
+
|
319
|
+
def to_nil
|
320
|
+
self.empty? ? nil : self
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
Hash.class_eval do
|
326
|
+
include HashUtils
|
327
|
+
end
|
328
|
+
|
329
|
+
if defined? HashWithIndifferentAccess
|
330
|
+
HashWithIndifferentAccess.class_eval do
|
331
|
+
include HashUtils
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
module ArrayUtils
|
336
|
+
def filter_include!(aValues,aArray=nil)
|
337
|
+
aArray ||= self
|
338
|
+
if aValues.is_a? Array
|
339
|
+
return aArray if aValues.empty?
|
340
|
+
return aArray.delete_if {|v| not aValues.include? v }
|
341
|
+
elsif aValues.is_a? Regexp
|
342
|
+
return aArray.delete_if {|v| not v =~ aValues }
|
343
|
+
else
|
344
|
+
return filter_include!([aValues],aArray)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def filter_include(aValues,aArray=nil)
|
349
|
+
aArray ||= self
|
350
|
+
filter_include!(aValues,aArray.clone)
|
351
|
+
end
|
352
|
+
|
353
|
+
def filter_exclude!(aValues,aArray=nil)
|
354
|
+
aArray ||= self
|
355
|
+
if aValues.is_a? Array
|
356
|
+
return aArray if aValues.empty?
|
357
|
+
return aArray.delete_if {|v| aValues.include? v }
|
358
|
+
elsif aValues.is_a? Regexp
|
359
|
+
return aArray.delete_if {|v| v =~ aValues }
|
360
|
+
else
|
361
|
+
return filter_exclude!([aValues],aArray)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def filter_exclude(aValues,aArray=nil)
|
366
|
+
aArray ||= self
|
367
|
+
filter_exclude!(aValues,aArray.clone)
|
368
|
+
end
|
369
|
+
|
370
|
+
def to_nil
|
371
|
+
self.empty? ? nil : self
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
Array.class_eval do
|
377
|
+
include ArrayUtils
|
378
|
+
|
379
|
+
# fixes a memory leak in shift in Ruby 1.8 - should be fixed in 1.9
|
380
|
+
# see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/216055
|
381
|
+
def shift()
|
382
|
+
delete_at(0)
|
383
|
+
end
|
384
|
+
|
385
|
+
end
|
386
|
+
|
387
|
+
Kernel.class_eval do
|
388
|
+
def is_windows?
|
389
|
+
RUBY_PLATFORM =~ /(win|w)32$/ ? true : false
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
if defined? ActiveRecord
|
394
|
+
ActiveRecord::Base.class_eval do
|
395
|
+
|
396
|
+
def self.find_any_id(aId)
|
397
|
+
with_exclusive_scope { find(:first, {:conditions => {:id => aId}}) }
|
398
|
+
end
|
399
|
+
|
400
|
+
def self.find_any_all(aOptions={})
|
401
|
+
with_exclusive_scope { find(:all, aOptions) }
|
402
|
+
end
|
403
|
+
|
404
|
+
def self.find_ids(aIds)
|
405
|
+
find(:all, {:conditions=> ["id in (?)",aIds.join(',')]})
|
406
|
+
end
|
407
|
+
|
408
|
+
def self.find_any_ids(aIds)
|
409
|
+
with_exclusive_scope { find(:all, {:conditions=> ["id in (?)",aIds.join(',')]}) }
|
410
|
+
end
|
411
|
+
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
Fixnum.class_eval do
|
416
|
+
|
417
|
+
def to_nil
|
418
|
+
self==0 ? nil : self
|
419
|
+
end
|
420
|
+
|
421
|
+
def to_b(aDefault=false)
|
422
|
+
self==0 ? false : true
|
423
|
+
end
|
424
|
+
|
425
|
+
end
|
426
|
+
|
427
|
+
Bignum.class_eval do
|
428
|
+
|
429
|
+
def to_nil
|
430
|
+
self==0 ? nil : self
|
431
|
+
end
|
432
|
+
|
433
|
+
def to_b(aDefault=false)
|
434
|
+
self==0 ? false : true
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
438
|
+
|
439
|
+
NilClass.class_eval do
|
440
|
+
|
441
|
+
def to_nil
|
442
|
+
nil
|
443
|
+
end
|
444
|
+
|
445
|
+
def to_b(aDefault=false)
|
446
|
+
false
|
447
|
+
end
|
448
|
+
|
449
|
+
end
|
450
|
+
|
451
|
+
TrueClass.class_eval do
|
452
|
+
|
453
|
+
def to_nil
|
454
|
+
self
|
455
|
+
end
|
456
|
+
|
457
|
+
def to_b(aDefault=false)
|
458
|
+
self
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|
462
|
+
|
463
|
+
FalseClass.class_eval do
|
464
|
+
|
465
|
+
def to_nil
|
466
|
+
nil
|
467
|
+
end
|
468
|
+
|
469
|
+
def to_b(aDefault=false)
|
470
|
+
self
|
471
|
+
end
|
472
|
+
|
473
|
+
end
|
474
|
+
|
475
|
+
|
476
|
+
Math.module_eval do
|
477
|
+
def self.max(a, b)
|
478
|
+
a > b ? a : b
|
479
|
+
end
|
480
|
+
|
481
|
+
def self.min(a, b)
|
482
|
+
a < b ? a : b
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
@@ -0,0 +1,334 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'logger'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
#require 'buzzcorej/logging'
|
6
|
+
|
7
|
+
module MiscUtils
|
8
|
+
|
9
|
+
def self.logger
|
10
|
+
@logger || @logger = Logger.new(STDERR)
|
11
|
+
end
|
12
|
+
|
13
|
+
# applies the given block to key/value pairs included/excluded by the given parameters
|
14
|
+
# aSource must be a hash, and may contain hashes which will be recursively processed.
|
15
|
+
# aInclude/aExclude may be nil, an array of selected keys, or a hash containing arrays of keys for inner hashes of aSource
|
16
|
+
# When aInclude/aExclude are a hash, non-hash source values may be selected by passing a value of true. Hash source values
|
17
|
+
# will be selected as a whole (all keys) when true is passed.
|
18
|
+
# input = { 'a' => 1, 'b' => {'x' => 9, 'y' => 8}, 'c' => 3 }
|
19
|
+
# filter_multilevel_hash(input,['a','b'],{'b'=>['y']}) {|h,k,v| h[k] = true}
|
20
|
+
# input now = { 'a' => true, 'b' => {'x' => true, 'y' => 8}, 'c' => 3 }
|
21
|
+
def self.filter_multilevel_hash(aSource,aInclude=nil,aExclude=nil,&block)
|
22
|
+
aSource.each do |key,value|
|
23
|
+
next if aInclude.is_a?(Array) and !aInclude.include?(key) # skip if not in aInclude array
|
24
|
+
next if aExclude.is_a?(Array) and aExclude.include?(key) # skip if in aExclude array
|
25
|
+
next if aExclude.is_a?(Hash) and aExclude[key]==true # skip if in aExclude hash with value=true
|
26
|
+
next if aInclude.is_a?(Hash) and !aInclude.include?(key) # skip if not in aInclude hash at all
|
27
|
+
if value.is_a?(Hash) # value is hash so recursively apply filter
|
28
|
+
filter_multilevel_hash(
|
29
|
+
value,
|
30
|
+
aInclude.is_a?(Hash) && (f = aInclude[key]) ? f : nil, # pass include array if provided for key
|
31
|
+
aExclude.is_a?(Hash) && (f = aExclude[key]) ? f : nil, # pass exclude array if provided for key
|
32
|
+
&block
|
33
|
+
)
|
34
|
+
else
|
35
|
+
yield(aSource,key,value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.temp_file(aExt=nil,aDir=nil)
|
41
|
+
aExt ||= '.tmp'
|
42
|
+
File.expand_path(("%08X" % rand(0x3FFFFFFF)) + aExt, aDir||Dir.tmpdir)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.make_temp_file(aName=nil,aDir=nil,aContent=nil)
|
46
|
+
filename = aName ? File.expand_path(aName,aDir || Dir.tmpdir) : temp_file(nil,aDir)
|
47
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
48
|
+
aContent ||= "content of "+filename
|
49
|
+
string_to_file(aContent,filename)
|
50
|
+
filename
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.make_temp_dir(aPrefix='')
|
54
|
+
new_dir = nil
|
55
|
+
begin
|
56
|
+
new_dir = File.join(Dir.tmpdir,aPrefix+("%08X" % rand(0x3FFFFFFF)))
|
57
|
+
end until new_dir && !File.exists?(new_dir)
|
58
|
+
Dir.mkdir new_dir
|
59
|
+
return new_dir
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.mkdir?(aPath,aPermissions)
|
63
|
+
if File.exists?(aPath)
|
64
|
+
File.chmod(aPermissions, aPath)
|
65
|
+
else
|
66
|
+
Dir.mkdir(aPath, aPermissions)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#def self.set_permissions_cmd(aFilepath,aUser=nil,aGroup=nil,aMode=nil,aSetGroupId=false,aSudo=true)
|
71
|
+
# cmd = []
|
72
|
+
# if aGroup
|
73
|
+
# cmd << (aUser ? "#{aSudo ? sudo : ''} chown #{aUser}:#{aGroup}" : "#{aSudo ? sudo : ''} chgrp #{aGroup}") + " #{aFilepath}"
|
74
|
+
# else
|
75
|
+
# cmd << "#{aSudo ? sudo : ''} chown #{aUser} #{aFilepath}" if aUser
|
76
|
+
# end
|
77
|
+
# cmd << "#{aSudo ? sudo : ''} chmod #{aMode.to_s} #{aFilepath}" if aMode
|
78
|
+
# cmd << "#{aSudo ? sudo : ''} chmod g+s #{aFilepath}" if aSetGroupId
|
79
|
+
# cmd.join(' && ')
|
80
|
+
#end
|
81
|
+
|
82
|
+
def self.string_to_file(aString,aFilename)
|
83
|
+
File.open(aFilename,'wb') {|file| file.write aString }
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.string_from_file(aFilename)
|
87
|
+
result = nil
|
88
|
+
File.open(aFilename, "rb") { |f| result = f.read }
|
89
|
+
# return result && result[0..-2] # quick hack to stop returning false \n at end UPDATE: this is causing problems now
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.sniff_seperator(aPath)
|
93
|
+
result = 0.upto(aPath.length-1) do |i|
|
94
|
+
char = aPath[i,1]
|
95
|
+
break char if char=='\\' || char=='/'
|
96
|
+
end
|
97
|
+
result = File::SEPARATOR if result==0
|
98
|
+
return result
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.append_slash(aPath,aSep=nil)
|
102
|
+
aSep = sniff_seperator(aPath) unless aSep
|
103
|
+
last_char = aPath[-1,1]
|
104
|
+
aPath += aSep unless last_char=='\\' || last_char=='/'
|
105
|
+
return aPath
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.remove_slash(aPath)
|
109
|
+
last_char = aPath[-1,1]
|
110
|
+
aPath = aPath[0..-2] if last_char=='\\' || last_char=='/'
|
111
|
+
return aPath
|
112
|
+
end
|
113
|
+
|
114
|
+
# Remove base dir from given path. Result will be relative to base dir and not have a leading or trailing slash
|
115
|
+
#'/a/b/c','/a' = 'b/c'
|
116
|
+
#'/a/b/c','/' = 'a/b/c'
|
117
|
+
#'/','/' = ''
|
118
|
+
def self.path_debase(aPath,aBase)
|
119
|
+
aBase = MiscUtils::append_slash(aBase)
|
120
|
+
aPath = MiscUtils::remove_slash(aPath) unless aPath=='/'
|
121
|
+
aPath[0,aBase.length]==aBase ? aPath[aBase.length,aPath.length-aBase.length] : aPath
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.path_rebase(aPath,aOldBase,aNewBase)
|
125
|
+
rel_path = path_debase(aPath,aOldBase)
|
126
|
+
append_slash(aNewBase)+rel_path
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.path_combine(aBasePath,aPath)
|
130
|
+
return aBasePath if !aPath
|
131
|
+
return aPath if !aBasePath
|
132
|
+
return path_relative?(aPath) ? File.join(aBasePath,aPath) : aPath
|
133
|
+
end
|
134
|
+
|
135
|
+
# make path real according to file system
|
136
|
+
def self.real_path(aPath)
|
137
|
+
(path = Pathname.new(File.expand_path(aPath))) && path.realpath.to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
# takes a path and combines it with a root path (which defaults to Dir.pwd) unless it is absolute
|
141
|
+
# the final result is then expanded
|
142
|
+
def self.canonize_path(aPath,aRootPath=nil)
|
143
|
+
path = path_combine(aRootPath,aPath)
|
144
|
+
path = real_path(path) if path
|
145
|
+
path
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.find_upwards(aStartPath,aPath)
|
149
|
+
curr_path = File.expand_path(aStartPath)
|
150
|
+
while curr_path && !(test_path_exists = File.exists?(test_path = File.join(curr_path,aPath))) do
|
151
|
+
curr_path = MiscUtils.path_parent(curr_path)
|
152
|
+
end
|
153
|
+
curr_path && test_path_exists ? test_path : nil
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# allows special symbols in path
|
158
|
+
# currently only ... supported, which looks upward in the filesystem for the following relative path from the basepath
|
159
|
+
def self.expand_magic_path(aPath,aBasePath=nil)
|
160
|
+
aBasePath ||= Dir.pwd
|
161
|
+
path = aPath
|
162
|
+
if path.begins_with?('...')
|
163
|
+
rel_part = StringUtils.split3(path,/\.\.\.[\/\\]/)[2]
|
164
|
+
path = find_upwards(aBasePath,rel_part)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.path_parent(aPath)
|
169
|
+
return nil if is_root_path?(aPath)
|
170
|
+
MiscUtils.append_slash(File.dirname(MiscUtils.remove_slash(File.expand_path(aPath))))
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.simple_dir_name(aPath)
|
174
|
+
File.basename(remove_slash(aPath))
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.simple_file_name(aPath)
|
178
|
+
f = File.basename(aPath)
|
179
|
+
dot = f.index('.')
|
180
|
+
return dot ? f[0,dot] : f
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.path_parts(aPath)
|
184
|
+
sep = sniff_seperator(aPath)
|
185
|
+
aPath.split(sep)
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.file_extension(aFile,aExtended=true)
|
189
|
+
f = File.basename(aFile)
|
190
|
+
dot = aExtended ? f.index('.') : f.rindex('.')
|
191
|
+
return dot ? f[dot+1..-1] : f
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.file_no_extension(aFile,aExtended=true)
|
195
|
+
ext = file_extension(aFile,aExtended)
|
196
|
+
return aFile.chomp('.'+ext)
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.file_change_ext(aFile,aExt,aExtend=false)
|
200
|
+
file_no_extension(aFile,false)+(aExtend ? '.'+aExt+'.'+file_extension(aFile,false) : '.'+aExt)
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.platform
|
204
|
+
RUBY_PLATFORM.scan(/-(.+)$/).flatten.first
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.windows_path(aPath)
|
208
|
+
aPath.gsub('/','\\')
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.ruby_path(aPath)
|
212
|
+
aPath.gsub('\\','/')
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.is_uri?(aString)
|
216
|
+
/^[a-zA-Z0-9+_]+\:\/\// =~ aString ? true : false
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.is_root_path?(aPath)
|
220
|
+
if is_windows?
|
221
|
+
(aPath =~ /^[a-zA-Z]\:[\\\/]$/)==0
|
222
|
+
else
|
223
|
+
aPath == '/'
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.native_path(aPath)
|
228
|
+
is_windows? ? windows_path(aPath) : ruby_path(aPath)
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.path_relative?(aPath)
|
232
|
+
return false if aPath[0,1]=='/'
|
233
|
+
return false if aPath =~ /^[a-zA-Z]:/
|
234
|
+
return true
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.path_absolute?(aPath)
|
238
|
+
!path_relative(aPath)
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.is_windows?
|
242
|
+
platform=='mswin32'
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.get_files(aArray,aPath,aFullPath=true,aRootPath=nil,&block)
|
246
|
+
#puts "get_files: aPath='#{aPath}'"
|
247
|
+
if aRootPath
|
248
|
+
abssrcpath = path_combine(aRootPath,aPath)
|
249
|
+
else
|
250
|
+
abssrcpath = aRootPath = aPath
|
251
|
+
aPath = nil
|
252
|
+
end
|
253
|
+
return aArray if !File.exists?(abssrcpath)
|
254
|
+
#abssrcpath is real path to query
|
255
|
+
#aRootPath is highest level path
|
256
|
+
#aPath is current path relative to aRootPath
|
257
|
+
Dir.new(abssrcpath).to_a.each do |file|
|
258
|
+
next if ['.','..'].include? file
|
259
|
+
fullpath = File.join(abssrcpath,file)
|
260
|
+
resultpath = aFullPath ? fullpath : path_combine(aPath,file)
|
261
|
+
if !block_given? || yield(resultpath)
|
262
|
+
if FileTest.directory?(fullpath)
|
263
|
+
block_given? ? get_files(aArray,path_combine(aPath,file),aFullPath,aRootPath,&block) : get_files(aArray,path_combine(aPath,file),aFullPath,aRootPath)
|
264
|
+
else
|
265
|
+
aArray << resultpath
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
return aArray
|
270
|
+
end
|
271
|
+
|
272
|
+
def self.recursive_file_list(aPath,aFullPath=true,&block)
|
273
|
+
block_given? ? get_files([],aPath,aFullPath,nil,&block) : get_files([],aPath,aFullPath)
|
274
|
+
end
|
275
|
+
|
276
|
+
# returns true if aPath1 and aPath2 are the same path (doesn't query file system)
|
277
|
+
# both must be absolute or both relative
|
278
|
+
def self.path_same(aPath1,aPath2)
|
279
|
+
return nil unless path_relative?(aPath1) == path_relative?(aPath2)
|
280
|
+
remove_slash(aPath1) == remove_slash(aPath2)
|
281
|
+
end
|
282
|
+
|
283
|
+
# returns true if aPath is under aPathParent
|
284
|
+
# both must be absolute or both relative
|
285
|
+
def self.path_ancestor(aPathParent,aPath)
|
286
|
+
return nil unless path_relative?(aPathParent) == path_relative?(aPath)
|
287
|
+
aPath.index(append_slash(aPathParent))==0
|
288
|
+
end
|
289
|
+
|
290
|
+
# returns the lowest path containing all files (assumes aFiles contains only absolute paths)
|
291
|
+
def self.file_list_ancestor(aFiles)
|
292
|
+
files = aFiles.is_a?(Hash) ? aFiles.keys : aFiles
|
293
|
+
result = File.dirname(files.first)
|
294
|
+
files.each do |fp|
|
295
|
+
filedir = File.dirname(fp)
|
296
|
+
while path_same(result,filedir)==false && path_ancestor(result,filedir)==false
|
297
|
+
result = path_parent(result)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
result
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.path_match(aPath,aPatterns)
|
304
|
+
aPatterns = [aPatterns] unless aPatterns.is_a? Array
|
305
|
+
aPatterns.any? do |pat|
|
306
|
+
case pat
|
307
|
+
when String then aPath[0,pat.length] == pat
|
308
|
+
when Regexp then aPath =~ pat
|
309
|
+
else false
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
# takes a hash and returns a single closed tag containing the hash pairs as attributes, correctly encoded
|
315
|
+
def self.hash_to_xml_tag(aName,aHash)
|
316
|
+
atts = ''
|
317
|
+
aHash.each do |k,v|
|
318
|
+
atts += ' ' + k.to_s + "=\"#{v.to_s.to_xs}\""
|
319
|
+
end
|
320
|
+
"<#{aName}#{atts}/>"
|
321
|
+
end
|
322
|
+
|
323
|
+
def self.filelist_from_patterns(aPatterns,aBasePath)
|
324
|
+
return [] unless aPatterns
|
325
|
+
aPatterns = [aPatterns] unless aPatterns.is_a? Array
|
326
|
+
|
327
|
+
aPatterns.map do |fp|
|
328
|
+
fp = File.expand_path(fp,aBasePath) # relative to rails root
|
329
|
+
fp = FileList[fp] if fp['*'] || fp['?']
|
330
|
+
fp
|
331
|
+
end.flatten
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# This sorts out the issues of require'ing files in Ruby
|
2
|
+
# 1) on one line, you specify all the paths you need
|
3
|
+
# 2) Relative paths will be relative to the file you are in, absolute paths also supported
|
4
|
+
# 3) Paths will be expanded
|
5
|
+
# 4) Paths will only be added if they don't already exist
|
6
|
+
#
|
7
|
+
module ::Kernel
|
8
|
+
|
9
|
+
# returns full path given relative to $LOAD_PATH
|
10
|
+
def require_which(aFilepath)
|
11
|
+
aFilepath += '.rb'
|
12
|
+
$LOAD_PATH.each do |dir|
|
13
|
+
full_path = File.expand_path(File.join(dir,aFilepath))
|
14
|
+
return full_path if File.exist? full_path
|
15
|
+
end
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def require_paths(*aArgs)
|
20
|
+
caller_dir = File.dirname(File.expand_path(caller.first.sub(/:[0-9]+.*/,'')))
|
21
|
+
aArgs.each do |aPath|
|
22
|
+
aPath = File.expand_path(aPath,caller_dir)
|
23
|
+
$LOAD_PATH << aPath unless $LOAD_PATH.include?(aPath)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def require_paths_first(*aArgs)
|
28
|
+
caller_dir = File.dirname(File.expand_path(caller.first.sub(/:[0-9]+.*/,'')))
|
29
|
+
paths = []
|
30
|
+
aArgs.each do |aPath|
|
31
|
+
aPath = File.expand_path(aPath,caller_dir)
|
32
|
+
paths << aPath
|
33
|
+
end
|
34
|
+
paths.each do |p|
|
35
|
+
$LOAD_PATH.insert(0,p)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module StringUtils
|
2
|
+
def self.crop(aString,aLength,aEllipsis=true,aConvertNil=true)
|
3
|
+
return aConvertNil ? ' '*aLength : nil if !aString
|
4
|
+
|
5
|
+
increase = aLength-aString.length
|
6
|
+
return aString+' '*increase if increase>=0
|
7
|
+
return aEllipsis ? aString[0,aLength-3]+'...' : aString[0,aLength]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.simplify_whitespace(aText)
|
11
|
+
aText.gsub(/[ \n\t\r]+/,' ').strip
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.crop_to_word_count(aText,aWordCount)
|
15
|
+
aText = simplify_whitespace(aText)
|
16
|
+
matches = aText.scan_md(/[^\w-]+/)
|
17
|
+
match = matches[aWordCount-1]
|
18
|
+
result = (match ? match.pre_match : aText)
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
# aTemplate is a string containing tokens like ${SOME_TOKEN}
|
23
|
+
# aValues is a hash of token names eg. 'SOME_TOKEN' and their values to substitute
|
24
|
+
def self.render_template(aTemplate,aValues)
|
25
|
+
# get positions of tokens
|
26
|
+
result = aTemplate.gsub(/\$\{(.*?)\}/) do |s|
|
27
|
+
key = s[2..-2]
|
28
|
+
rep = (aValues[key] || s)
|
29
|
+
#puts "replacing #{s} with #{rep}"
|
30
|
+
rep
|
31
|
+
end
|
32
|
+
#puts "rendered :\n#{result}"
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.clean_number(aString)
|
37
|
+
aString.gsub(/[^0-9.-]/,'')
|
38
|
+
end
|
39
|
+
|
40
|
+
# supply a block with 2 parameters, and it will get called for each char as an integer
|
41
|
+
def self.each_unicode_char(aString)
|
42
|
+
len = 1
|
43
|
+
index = 0
|
44
|
+
char = 0
|
45
|
+
aString.each_byte do |b|
|
46
|
+
if index==0
|
47
|
+
len = 1
|
48
|
+
len = 2 if b & 0b11000000 != 0
|
49
|
+
len = 3 if b & 0b11100000 != 0
|
50
|
+
len = 4 if b & 0b11110000 != 0
|
51
|
+
char = 0
|
52
|
+
end
|
53
|
+
|
54
|
+
char |= b << index*8
|
55
|
+
|
56
|
+
yield(char,len) if index==len-1 # last byte; char is complete
|
57
|
+
|
58
|
+
index += 1
|
59
|
+
index = 0 if index >= len
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# given ('abcdefg','c.*?e') returns ['ab','cde','fg'] so you can manipulate the head, match and tail seperately, and potentially rejoin
|
64
|
+
def self.split3(aString,aPattern,aOccurence=0)
|
65
|
+
matches = aString.scan_md(aPattern)
|
66
|
+
match = matches[aOccurence]
|
67
|
+
parts = (match ? [match.pre_match,match.to_s,match.post_match] : [aString,nil,''])
|
68
|
+
|
69
|
+
if !block_given? # return head,match,tail
|
70
|
+
parts
|
71
|
+
else # return string
|
72
|
+
parts[1] = yield *parts if match
|
73
|
+
parts.join
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# truncates a string to the given length by looking for the previous space.
|
78
|
+
def self.word_safe_truncate(aString,aMaxLength)
|
79
|
+
return nil if !aString
|
80
|
+
return aString if aString.length <= aMaxLength
|
81
|
+
posLastSpace = aString.rindex(/[ \t]/,aMaxLength)
|
82
|
+
return aString[0,aMaxLength] if !posLastSpace
|
83
|
+
aString[0,posLastSpace]
|
84
|
+
end
|
85
|
+
|
86
|
+
# replaces all tabs with spaces, and reduces multiple spaces to a single space
|
87
|
+
def self.reduce_whitespace(aText)
|
88
|
+
aText = aText.gsub("\t"," ") # replace tabs with spaces
|
89
|
+
aText.strip!
|
90
|
+
aText.squeeze!(' ')
|
91
|
+
aText
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# when you want to load the live version of buzzcorej, not the gem :
|
2
|
+
# require File.join(File.dirname(__FILE__),'../../../../../buzzcorej/lib/buzzcorej_dev.rb');
|
3
|
+
require File.join(File.dirname(__FILE__),'buzzcorej/require_paths') # load require_paths early for next line
|
4
|
+
require_paths_first '.'
|
5
|
+
require 'buzzcorej'
|
6
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: buzzcorej
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- buzzware
|
@@ -42,9 +42,20 @@ extra_rdoc_files:
|
|
42
42
|
- LICENSE
|
43
43
|
- README.rdoc
|
44
44
|
files:
|
45
|
-
- lib/buzzcorej.rb
|
46
45
|
- LICENSE
|
47
46
|
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- buzzcorej.gemspec
|
50
|
+
- buzzcorej.vpj
|
51
|
+
- buzzcorej.vpw
|
52
|
+
- lib/buzzcorej.rb
|
53
|
+
- lib/buzzcorej/enum.rb
|
54
|
+
- lib/buzzcorej/extend_base_classes.rb
|
55
|
+
- lib/buzzcorej/misc_utils.rb
|
56
|
+
- lib/buzzcorej/require_paths.rb
|
57
|
+
- lib/buzzcorej/string_utils.rb
|
58
|
+
- lib/buzzcorej_dev.rb
|
48
59
|
- test/test_helper.rb
|
49
60
|
has_rdoc: true
|
50
61
|
homepage: http://github.com/buzzware/buzzcorej
|