buzzcorej 0.0.1 → 0.0.2

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.
@@ -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
@@ -0,0 +1,2 @@
1
+ 0.0.2
2
+
@@ -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
+
@@ -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="&amp;Compile"
14
+ CaptureOutputWith="ProcessBuffer"
15
+ SaveOption="SaveCurrent"
16
+ RunFromDir="%rw">
17
+ <Exec/>
18
+ </Target>
19
+ <Target
20
+ Name="Build"
21
+ MenuCaption="&amp;Build"
22
+ CaptureOutputWith="ProcessBuffer"
23
+ SaveOption="SaveWorkspaceFiles"
24
+ RunFromDir="%rw">
25
+ <Exec/>
26
+ </Target>
27
+ <Target
28
+ Name="Rebuild"
29
+ MenuCaption="&amp;Rebuild"
30
+ CaptureOutputWith="ProcessBuffer"
31
+ SaveOption="SaveWorkspaceFiles"
32
+ RunFromDir="%rw">
33
+ <Exec/>
34
+ </Target>
35
+ <Target
36
+ Name="Debug"
37
+ MenuCaption="&amp;Debug"
38
+ SaveOption="SaveNone"
39
+ RunFromDir="%rw">
40
+ <Exec/>
41
+ </Target>
42
+ <Target
43
+ Name="Execute"
44
+ MenuCaption="E&amp;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,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="&amp;Compile"
14
+ CaptureOutputWith="ProcessBuffer"
15
+ SaveOption="SaveCurrent"
16
+ RunFromDir="%rw">
17
+ <Exec/>
18
+ </Target>
19
+ <Target
20
+ Name="Build"
21
+ MenuCaption="&amp;Build"
22
+ CaptureOutputWith="ProcessBuffer"
23
+ SaveOption="SaveWorkspaceFiles"
24
+ RunFromDir="%rw">
25
+ <Exec/>
26
+ </Target>
27
+ <Target
28
+ Name="Rebuild"
29
+ MenuCaption="&amp;Rebuild"
30
+ CaptureOutputWith="ProcessBuffer"
31
+ SaveOption="SaveWorkspaceFiles"
32
+ RunFromDir="%rw">
33
+ <Exec/>
34
+ </Target>
35
+ <Target
36
+ Name="Debug"
37
+ MenuCaption="&amp;Debug"
38
+ SaveOption="SaveNone"
39
+ RunFromDir="%rw">
40
+ <Exec/>
41
+ </Target>
42
+ <Target
43
+ Name="Execute"
44
+ MenuCaption="E&amp;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: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
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