cldwalker-core 0.0.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/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT LICENSE
2
+
3
+ Copyright (c) 2008 Gabriel Horner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,80 @@
1
+ Description
2
+ ===========
3
+
4
+ My extensions to core and standard ruby 1.8 classes, similar to the facets and activesupport gems.
5
+ Although my extensions are probably nothing new, they are unobtrusive (monkeypatching is up to you)
6
+ and have basic checks for preventing method name collision.
7
+ So if you're not feeling shy, monkeypatch away:
8
+
9
+ irb>> require 'core'
10
+ true
11
+ irb>> Core.adds_to Array
12
+ Array
13
+ irb>> Core.ancestors
14
+ => [Array, Core::Array, Enumerable, Object, PP::ObjectMixin, Kernel]
15
+
16
+ And if you're not feeling your monkey-fu:
17
+
18
+ irb>> class Base; class Array < Array; end; end
19
+ => nil
20
+ irb>> Core.add_to Base::Array, :with=>Core::Array
21
+ =>Base::Array
22
+ irb>> Base::Array.ancestors
23
+ =>[Base::Array,Array, Core::Array, Enumerable, Object, PP::ObjectMixin, Kernel]
24
+
25
+ So what happens when it's four o'clock in the morning and you monkeypatch the wrong way?:
26
+
27
+ irb>> module Core::Array; def is_a?(*args); puts "dunno, i'm sleepy!"; end; end
28
+ nil
29
+ irb>> Core.adds_to Array
30
+ Couldn't include Core::Array into Array because the following methods conflict:
31
+ map
32
+
33
+ Phew, that was a close one. But wait, I really do think I know what I'm doing:
34
+
35
+ irb>> Core.adds_to Array, :force=>true
36
+ Array
37
+ irb>> [1,2].is_a?(Array)
38
+ dunno, i'm sleepy!
39
+ =>nil
40
+
41
+ Hopefully you'll use the force option more wisely.
42
+
43
+ Your Core
44
+ =========
45
+ If you'd like to wrap your own core extensions in say the original namespace MyCore:
46
+
47
+ MyCore.send :include, Core::Loader
48
+
49
+ You'll then be able to extend classes as in the examples above, replacing Core with MyCore.
50
+ To take advantage of the auto-requiring done by Core::Loader, place your extensions
51
+ in a directory mycore/ and make sure your $LOAD\_PATH contains the directory mycore.
52
+ In other words, `require 'mycore/array'` should be valid.
53
+
54
+ To wrap up your methods for MyCore, see my extensions or use this template:
55
+
56
+ #in mycore/array.rb
57
+ module MyCore
58
+ #extensions for Array's
59
+ module Array
60
+ def blah
61
+ end
62
+ #....
63
+ end
64
+ end
65
+
66
+
67
+ Limitations
68
+ ===========
69
+
70
+ Checks for method name collisions currently use *instance\_methods and *methods of a class.
71
+ Patches for more thorough checks are welcome.
72
+
73
+ Todo
74
+ ====
75
+
76
+ * Support extending class methods of the extended class.
77
+ * Import/Upgrade my old tests for my extension classes.
78
+ * Would be nice to:
79
+ ** Provide aliasing for methods to avoid method name clashes.
80
+ ** Make it easier to share/install core extensions made by others.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ begin
5
+ require 'rcov/rcovtask'
6
+
7
+ Rcov::RcovTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ t.rcov_opts = ["-T -x '/Library/Ruby/*'"]
11
+ t.verbose = true
12
+ end
13
+ rescue LoadError
14
+ puts "Rcov not available. Install it for rcov-related tasks with: sudo gem install rcov"
15
+ end
16
+
17
+ begin
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |s|
20
+ s.name = "core"
21
+ s.description = "My extensions to core ruby classes, similar to the facets gem."
22
+ s.summary = s.description
23
+ s.email = "gabriel.horner@gmail.com"
24
+ s.homepage = "http://github.com/cldwalker/core"
25
+ s.authors = ["Gabriel Horner"]
26
+ s.files = FileList["VERSION.yml", "Rakefile", "README.markdown", "LICENSE.txt", "{bin,lib}/**/*"]
27
+ s.has_rdoc = true
28
+ s.extra_rdoc_files = ["README.markdown", "LICENSE.txt", "TODO.txt"]
29
+ end
30
+
31
+ rescue LoadError
32
+ puts "Jeweler not available. Install it for jeweler-related tasks with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
33
+ end
34
+
35
+ Rake::TestTask.new do |t|
36
+ t.libs << 'lib'
37
+ t.pattern = 'test/**/*_test.rb'
38
+ t.verbose = false
39
+ end
40
+
41
+ Rake::RDocTask.new do |rdoc|
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = 'test'
44
+ rdoc.options << '--line-numbers' << '--inline-source'
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
49
+ task :default => :test
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
data/lib/core/array.rb ADDED
@@ -0,0 +1,105 @@
1
+ module Core
2
+ module Array
3
+ # Allows you to specify ranges of elements and individual elements with one string, array starts at 1
4
+ # Example: choose first and fourth through eighth elements: '1,4-8'
5
+ def multislice(range,splitter=',',offset=nil)
6
+ #td: fix swallowing of empty lines
7
+ result = []
8
+ for r in range.split(splitter)
9
+ if r =~ /-/
10
+ min,max = r.split('-')
11
+ slice_min = min.to_i - 1
12
+ slice_min += offset if offset
13
+ result.push(*self.slice(slice_min, max.to_i - min.to_i + 1))
14
+ else
15
+ index = r.to_i - 1
16
+ index += offset if offset
17
+ result.push(self[index])
18
+ end
19
+ end
20
+ return result
21
+ end
22
+
23
+ # Converts an even # of array elements ie [1,2,3,4]
24
+ # or an array of array pairs ie [[1,2],[3,4]] to a hash.
25
+ def to_hash
26
+ Hash[*self.flatten]
27
+ end
28
+
29
+ # Returns hash mapping elements to the number of times they are found in the array.
30
+ def count_hash
31
+ count = {}
32
+ each {|e|
33
+ count[e] ||= 0
34
+ count[e] += 1
35
+ }
36
+ count
37
+ end
38
+
39
+ # Returns all possible paired permutations of elements disregarding order.
40
+ def permute
41
+ permutations = []
42
+ for i in (0 .. self.size - 1)
43
+ for j in (i + 1 .. self.size - 1)
44
+ permutations.push([self[i],self[j]])
45
+ end
46
+ end
47
+ permutations
48
+ end
49
+
50
+ # Assuming the array is an array of hashes, this returns a hash of the elements grouped by their
51
+ # values for the specified hash key.
52
+ def group_aoh_by_key(key,parallel_array=nil)
53
+ group = {}
54
+ each_with_index {|h,i|
55
+ value = h[key]
56
+ group[value] = [] if ! group.has_key?(value)
57
+ group[value].push((parallel_array.nil?) ? h : parallel_array[i])
58
+ }
59
+ group
60
+ end
61
+
62
+ # Maps the result of calling each element with the given method name and optional arguments.
63
+ def mmap(methodname,*args)
64
+ map {|e| e.send(methodname,*args) }
65
+ end
66
+
67
+ # Maps the result of calling the given function name with each element as its argument.
68
+ def fmap(function)
69
+ (function =~ /\./) ?
70
+ map {|e| eval "#{function}(e)" } :
71
+ map {|e| send(function,e) }
72
+ end
73
+
74
+ # Returns index of first element to match given regular expression.
75
+ def regindex(regex)
76
+ each_with_index {|e,i|
77
+ return i if e =~ /#{regex}/
78
+ }
79
+ nil
80
+ end
81
+
82
+ # Replaces element at index with values of given array.
83
+ def replace_index(i,array)
84
+ replace( (self[0, i] || []) + array + self[i + 1 .. -1] )
85
+ end
86
+
87
+ # Returns true if the array includes any from the first array and excludes all from the second.
88
+ def include_and_exclude?(do_include,dont_include=[])
89
+ include_any?(do_include) && exclude_all?(dont_include)
90
+ end
91
+
92
+ # Returns true if it has any elements in common with the given array.
93
+ def include_any?(arr)
94
+ #good for large sets w/ few matches
95
+ #! Set.new(self).intersection(arr).empty?
96
+ arr.any? {|e| self.include?(e) }
97
+ end
98
+
99
+
100
+ # Returns true if it has no elements in common with the given array.
101
+ def exclude_all?(arr)
102
+ ! include_any?(arr)
103
+ end
104
+ end
105
+ end
data/lib/core/class.rb ADDED
@@ -0,0 +1,18 @@
1
+ class Class
2
+ # Returns ancestors that aren't included modules and the class itself.
3
+ def real_ancestors
4
+ ancestors - included_modules - [self]
5
+ end
6
+
7
+ #Returns all objects of class.
8
+ def objects
9
+ object = []
10
+ ObjectSpace.each_object(self) {|e| object.push(e) }
11
+ object
12
+ end
13
+
14
+ #td: used to be :objects, change tb_* files to reflect change
15
+ def object_strings #:nodoc:
16
+ objects.map {|e| e.to_s}
17
+ end
18
+ end
data/lib/core/dir.rb ADDED
@@ -0,0 +1,63 @@
1
+ # All methods here take an optional directory argument, defaulting to the current directory.
2
+ class Dir
3
+ # Returns current directory with a '/' appended.
4
+ def self.mpwd
5
+ Dir.pwd + "/"
6
+ end
7
+
8
+ # Returns entries from simple_entries() that are directories.
9
+ def self.dir_children(dirname=mpwd)
10
+ self.simple_entries(dirname).find_all {|e|
11
+ File.directory?(File.join(dirname, e))
12
+ }
13
+ end
14
+
15
+ # Returns entries from simple_entries() that are files.
16
+ def self.file_children(dirname=mpwd)
17
+ self.simple_entries(dirname).find_all {|e|
18
+ File.file?(File.join(dirname,e))
19
+ }
20
+ end
21
+
22
+ # Returns everything in a directory that entries() would except
23
+ # for '.', '..' and vim's backup files ie files ending with ~ or .sw*.
24
+ # You should override this method to take advantage of methods based on it.
25
+ def self.simple_entries(dirname=mpwd)
26
+ dir_files = Dir.entries(dirname)
27
+ files = dir_files - ['.','..'] - dir_files.grep(/~$/) - dir_files.grep(/\.sw[o-z]$/)
28
+ end
29
+
30
+ # Returns entries from simple_entries() that are not symlinks.
31
+ def self.nonlink_entries(dirname=mpwd)
32
+ self.simple_entries(dirname).select {|e|
33
+ ! File.symlink?(File.join(dirname,e))
34
+ }
35
+ end
36
+
37
+ #Returns the full paths of simple_entries().
38
+ def self.full_entries(dirname=mpwd)
39
+ self.simple_entries(dirname).map {|e| File.join(dirname,e) }
40
+ end
41
+
42
+ # Returns all simple_entries under a directory for the specified depth. If no depth specified
43
+ # it'll return all entries under the directory.
44
+ def self.levels_of_children(dirname=mpwd,max_level=1000)
45
+ @max_level = max_level
46
+ @level_children = []
47
+ self.get_level_children(dirname,0)
48
+ @level_children
49
+ end
50
+
51
+ #used recursively by levels_of_children
52
+ def self.get_level_children(dirname,level) #:nodoc:
53
+ dir_children = self.full_entries(dirname)
54
+ @level_children += dir_children
55
+ if level < @max_level
56
+ dir_children.each {|e|
57
+ if File.directory?(e)
58
+ self.get_level_children(e,level + 1)
59
+ end
60
+ }
61
+ end
62
+ end
63
+ end
data/lib/core/file.rb ADDED
@@ -0,0 +1,11 @@
1
+ class File
2
+ # Converts file to string.
3
+ def self.to_string(file)
4
+ IO.read(file)
5
+ end
6
+
7
+ # Writes string to file.
8
+ def self.string_to_file(string,file)
9
+ File.open(file,'w') {|f| f.write(string) }
10
+ end
11
+ end
data/lib/core/hash.rb ADDED
@@ -0,0 +1,81 @@
1
+ class Hash
2
+ # For a hash whose keys are strings of Class names, this will delete any pairs that have
3
+ # nonexistant class names.
4
+ def validate_value_klass(klass)
5
+ self.each {|sid,obj|
6
+ if obj.class != Object.const_get(klass)
7
+ warn "object of '#{sid}' not a #{klass}"
8
+ self.delete(sid)
9
+ end
10
+ }
11
+ end
12
+
13
+ # Returns a hash which will set its values by calling each value with the given method and optional argument.
14
+ # If a block is passed, each value will be set the value returned by its block call.
15
+ def vmap(arg=nil,method='[]',&block)
16
+ new = {}
17
+ if block
18
+ self.each {|k,v|
19
+ v1 = yield(k,v)
20
+ new[k] = v1
21
+ }
22
+ else
23
+ self.each {|k,v|
24
+ new[k] = arg.nil? ? v.send(method) : v.send(method,arg)
25
+ }
26
+ end
27
+ new
28
+ end
29
+
30
+ # Same as vmap() but merges its results with the existing hash.
31
+ def vmap!(*args,&block)
32
+ self.update(vmap(*args,&block))
33
+ end
34
+
35
+ # For a hash whose values are arrays, this will return a hash with each value substituted by the
36
+ # size of the value.
37
+ def vsize
38
+ vmap(nil,'size')
39
+ end
40
+
41
+ # Same as pass_keys!() but replaces the hash with the resulting hash.
42
+ def only_keep(arr=[],opt={})
43
+ delete_keys!(self.keys - arr,opt)
44
+ end
45
+
46
+ def delete_keys!(arr=[],opt={}) #:nodoc:
47
+ deleted = {}
48
+ arr.each {|e|
49
+ puts "deleting #{e}" if opt[:verbose]
50
+ deleted[e] = self.delete(e) if has_key?(e)
51
+ }
52
+ deleted
53
+ end
54
+
55
+ # Returns a subset of the hash for the specified keys. These entries will be deleted from the
56
+ # original hash.
57
+ def pass_keys!(*keys)
58
+ delete_keys!(keys)
59
+ end
60
+
61
+ # For a hash whose values are arrays, this will set each unique element in a value array as a key
62
+ # and set its values to all the keys it occurred in.
63
+ # This is useful when modeling one to many relationships with keys
64
+ # and values.
65
+ def transform_many
66
+ b = {}
67
+ each {|k,arr|
68
+ #raise "#{arr.inspect} not an Array" if arr.class != Array
69
+ arr = [arr] if arr.class != Array
70
+ arr.each {|e|
71
+ b.has_key?(e) ? b[e].push(k) : b[e] = [k]
72
+ }
73
+ }
74
+ b
75
+ end
76
+
77
+ #Sorts hash by values, returning them as an array of array pairs.
78
+ def vsort
79
+ sort { |a,b| b[1]<=>a[1] }
80
+ end
81
+ end
data/lib/core/io.rb ADDED
@@ -0,0 +1,21 @@
1
+ class IO
2
+ #Returns array of lines up until the given string matches a line of the file.
3
+ def self.read_until(file,string)
4
+ f = self.readlines(file)
5
+ i = f.index(string) || 100000
6
+ f.slice(0,i)
7
+ end
8
+
9
+ #from output_catcher gem
10
+ def self.capture_stdout(&block)
11
+ original_stdout = $stdout
12
+ $stdout = fake = StringIO.new
13
+ begin
14
+ yield
15
+ ensure
16
+ $stdout = original_stdout
17
+ end
18
+ fake.string
19
+ end
20
+
21
+ end
data/lib/core/irb.rb ADDED
@@ -0,0 +1,29 @@
1
+ #from http://errtheblog.com/posts/9-drop-to-irb
2
+ # call with IRB.start_session(Kernel.binding) in script
3
+ require 'irb'
4
+
5
+ module IRB
6
+ def self.start_session(binding)
7
+ IRB.setup(nil)
8
+
9
+ workspace = WorkSpace.new(binding)
10
+
11
+ if @CONF[:SCRIPT]
12
+ irb = Irb.new(workspace, @CONF[:SCRIPT])
13
+ else
14
+ irb = Irb.new(workspace)
15
+ end
16
+
17
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
18
+ @CONF[:MAIN_CONTEXT] = irb.context
19
+
20
+ trap("SIGINT") do
21
+ irb.signal_handle
22
+ end
23
+
24
+ catch(:IRB_EXIT) do
25
+ irb.eval_input
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,19 @@
1
+ class Object
2
+ # A more versatile for of Object.const_get.
3
+ # Retrieves constant for given string, even if it's nested under classes.
4
+ def self.any_const_get(name)
5
+ begin
6
+ klass = Object
7
+ name.split('::').each {|e|
8
+ klass = klass.const_get(e)
9
+ }
10
+ klass
11
+ rescue; nil; end
12
+ end
13
+
14
+ #Reloads a file just as you would require it.
15
+ def reload(filename)
16
+ $".delete(filename + ".rb")
17
+ require(filename)
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ class String
2
+ # Counts # of times the given string is in the string. This is unlike String.count which
3
+ # only counts the given characters.
4
+ def count_any(str)
5
+ count = 0
6
+ self.gsub(str) {|s|
7
+ count += 1
8
+ str
9
+ }
10
+ count
11
+ end
12
+ end
data/lib/core.rb ADDED
@@ -0,0 +1,69 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+ module Core
4
+ module Loader
5
+ def self.included(base)
6
+ base.extend(self)
7
+ end
8
+
9
+ def adds_to(klass, options = {})
10
+ unless (extension_klass = options[:with] || get_extension_class(klass))
11
+ puts "No #{self} extension class found"
12
+ return false
13
+ end
14
+ conflicts = check_for_conflicts(klass, extension_klass)
15
+ if conflicts.empty? || options[:force]
16
+ klass.send :include, extension_klass
17
+ else
18
+ puts "Couldn't include #{extension_klass} into #{klass} because the following methods conflict:"
19
+ puts conflicts.sort.join(", ")
20
+ false
21
+ end
22
+ end
23
+ alias_method :add_to, :adds_to
24
+
25
+ def detect_extension_class(klass)
26
+ extension_klass = self.const_get(klass.to_s) rescue nil
27
+ extension_klass = nil if extension_klass == klass
28
+ extension_klass
29
+ end
30
+
31
+ def get_extension_class(klass)
32
+ unless (extension_klass = detect_extension_class(klass))
33
+ #try again but first by requiring possible file
34
+ begin; require("#{self.to_s.gsub('::','/').downcase}/#{klass.to_s.downcase}"); rescue(LoadError); end
35
+ extension_klass = detect_extension_class(klass)
36
+ end
37
+ extension_klass
38
+ end
39
+
40
+ def check_for_conflicts(klass, extension_klass)
41
+ if false #TODO: extension_klass.to_s =~ /ClassMethods/
42
+ else
43
+ all_instance_methods(klass) & all_instance_methods(extension_klass)
44
+ end
45
+ end
46
+
47
+ def all_instance_methods(klass)
48
+ klass.public_instance_methods + klass.private_instance_methods + klass.protected_instance_methods
49
+ end
50
+ end
51
+ end
52
+
53
+ Core.send :include, Core::Loader
54
+
55
+ __END__
56
+
57
+ #extend Array with Core::Array's ClassMethods + InstanceMethods
58
+ Core.adds_to Array
59
+
60
+ #extend MyArray from file
61
+ class My::Array
62
+ Core.adds_to self
63
+ end
64
+
65
+ #from console
66
+ Core.adds_to My::Array
67
+
68
+ #extend Array only with ClassMethods
69
+ Core.adds_to Array, :from=>Core::Array::ClassMethods
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cldwalker-core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel Horner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-28 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: My extensions to core ruby classes, similar to the facets gem.
17
+ email: gabriel.horner@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ - LICENSE.txt
25
+ - TODO.txt
26
+ files:
27
+ - VERSION.yml
28
+ - Rakefile
29
+ - README.markdown
30
+ - LICENSE.txt
31
+ - lib/core
32
+ - lib/core/array.rb
33
+ - lib/core/class.rb
34
+ - lib/core/dir.rb
35
+ - lib/core/file.rb
36
+ - lib/core/hash.rb
37
+ - lib/core/io.rb
38
+ - lib/core/irb.rb
39
+ - lib/core/object.rb
40
+ - lib/core/string.rb
41
+ - lib/core.rb
42
+ - TODO.txt
43
+ has_rdoc: true
44
+ homepage: http://github.com/cldwalker/core
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.2.0
66
+ signing_key:
67
+ specification_version: 2
68
+ summary: My extensions to core ruby classes, similar to the facets gem.
69
+ test_files: []
70
+