ruby_ext 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Rakefile +64 -0
  2. data/lib/ruby_ext/array.rb +13 -0
  3. data/lib/ruby_ext/basic_object.rb +22 -0
  4. data/lib/ruby_ext/class.rb +11 -0
  5. data/lib/ruby_ext/declarative_cache.rb +85 -0
  6. data/lib/ruby_ext/deep_clone.rb +62 -0
  7. data/lib/ruby_ext/extra_blank_slate.rb +16 -0
  8. data/lib/ruby_ext/file.rb +20 -0
  9. data/lib/ruby_ext/hash.rb +15 -0
  10. data/lib/ruby_ext/kernel.rb +69 -0
  11. data/lib/ruby_ext/micelaneous.rb +14 -0
  12. data/lib/ruby_ext/module.rb +119 -0
  13. data/lib/ruby_ext/multiple_inheritance.rb +76 -0
  14. data/lib/ruby_ext/must.rb +192 -0
  15. data/lib/ruby_ext/not_defined.rb +2 -0
  16. data/lib/ruby_ext/object.rb +8 -0
  17. data/lib/ruby_ext/observable2.rb +23 -0
  18. data/lib/ruby_ext/open_constructor.rb +51 -0
  19. data/lib/ruby_ext/open_object.rb +157 -0
  20. data/lib/ruby_ext/prepare_arguments.rb +105 -0
  21. data/lib/ruby_ext/prototype_inheritance.rb +110 -0
  22. data/lib/ruby_ext/should.rb +166 -0
  23. data/lib/ruby_ext/string.rb +44 -0
  24. data/lib/ruby_ext/symbol.rb +21 -0
  25. data/lib/ruby_ext/synchronize.rb +24 -0
  26. data/lib/ruby_ext/tuple.rb +7 -0
  27. data/lib/ruby_ext.rb +50 -0
  28. data/lib/spec_ext.rb +10 -0
  29. data/readme.md +66 -0
  30. data/spec/_prototype_inheritance_spec.rb +190 -0
  31. data/spec/array_spec.rb +8 -0
  32. data/spec/declarative_cache_spec.rb +115 -0
  33. data/spec/deep_clone_spec.rb +37 -0
  34. data/spec/helper.rb +20 -0
  35. data/spec/kernel_spec/TheNamespace/ClassA.rb +7 -0
  36. data/spec/kernel_spec/another_class.rb +5 -0
  37. data/spec/kernel_spec/the_namespace/class_b.rb +11 -0
  38. data/spec/kernel_spec.rb +53 -0
  39. data/spec/module_spec.rb +160 -0
  40. data/spec/multiple_inheritance_spec.rb +131 -0
  41. data/spec/must_spec.rb +29 -0
  42. data/spec/observable2_spec.rb +42 -0
  43. data/spec/open_constructor_spec.rb +36 -0
  44. data/spec/open_object_spec.rb +29 -0
  45. data/spec/prepare_arguments_spec.rb +46 -0
  46. data/spec/should_spec.rb +24 -0
  47. data/spec/spec.opts +2 -0
  48. data/spec/synchronize_spec.rb +80 -0
  49. metadata +127 -0
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rake'
2
+ require 'fileutils'
3
+ current_dir = File.expand_path(File.dirname(__FILE__))
4
+ Dir.chdir current_dir
5
+
6
+
7
+ #
8
+ # Specs
9
+ #
10
+ require 'spec/rake/spectask'
11
+
12
+ task :default => :spec
13
+
14
+ Spec::Rake::SpecTask.new('spec') do |t|
15
+ t.spec_files = FileList["spec/**/*_spec.rb"].select{|f| f !~ /\/_/}
16
+ t.libs = ["#{current_dir}/lib"]
17
+ end
18
+
19
+
20
+ #
21
+ # Gem
22
+ #
23
+ require 'rake/clean'
24
+ require 'rake/gempackagetask'
25
+
26
+ gem_options = {
27
+ :name => "ruby_ext",
28
+ :version => "0.4.6",
29
+ :summary => "Ruby language extensions",
30
+ :dependencies => %w(facets)
31
+ }
32
+
33
+ spec = Gem::Specification.new do |s|
34
+ gem_options.delete(:dependencies).each{|d| s.add_dependency d}
35
+ gem_options.each{|k, v| s.send "#{k}=", v}
36
+
37
+ s.author = "Alexey Petrushin"
38
+ s.homepage = "http://github.com/alexeypetrushin/#{gem_options[:name]}"
39
+ s.require_path = "lib"
40
+ s.files = (%w{Rakefile readme.md} + Dir.glob("{lib,spec}/**/*"))
41
+
42
+ s.platform = Gem::Platform::RUBY
43
+ s.has_rdoc = true
44
+ end
45
+
46
+ package_dir = "#{current_dir}/build"
47
+ Rake::GemPackageTask.new(spec) do |p|
48
+ p.need_tar = true if RUBY_PLATFORM !~ /mswin/
49
+ p.need_zip = true
50
+ p.package_dir = package_dir
51
+ end
52
+
53
+ task :push do
54
+ # dir = Dir.chdir package_dir do
55
+ gem_file = Dir.glob("#{package_dir}/#{gem_options[:name]}*.gem").first
56
+ system "gem push #{gem_file}"
57
+ # end
58
+ end
59
+
60
+ task :clean do
61
+ system "rm -r #{package_dir}"
62
+ end
63
+
64
+ task :release => [:gem, :push, :clean]
@@ -0,0 +1,13 @@
1
+ class Array
2
+ def sfilter *filters
3
+ filters = filters.first if filters.size == 1 and filters.first.is_a?(Array)
4
+ filters.collect!{|o| o.is_a?(Regexp) ? o : /#{Regexp.escape o}/}
5
+ self.select do |line|
6
+ !filters.any?{|re| line =~ re}
7
+ end
8
+ end
9
+
10
+ def self.wrap value
11
+ Array(value)
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ if defined? ::BasicObject
2
+ # A class with no predefined methods that behaves similarly to Builder's
3
+ # BlankSlate. Used for proxy classes.
4
+ class BasicObject < ::BasicObject
5
+ begin
6
+ undef_method :==
7
+ undef_method :equal?
8
+ rescue
9
+ end
10
+
11
+ # Let ActiveSupport::BasicObject at least raise exceptions.
12
+ def raise(*args)
13
+ ::Object.send(:raise, *args)
14
+ end
15
+ end
16
+ else
17
+ class BasicObject #:nodoc:
18
+ instance_methods.each do |m|
19
+ undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ Class.class_eval do
2
+ def alias name = nil
3
+ if name
4
+ name.must_be.a String
5
+ name.must_not_be.blank
6
+ @alias = name.to_s
7
+ else
8
+ @alias ||= self.name.split('::').last
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,85 @@
1
+ require 'monitor'
2
+
3
+ class Module
4
+ def cache_method *methods
5
+ DeclarativeCache.cache_method self, *methods
6
+ end
7
+
8
+ def cache_method_with_params *methods
9
+ DeclarativeCache.cache_method_with_params self, *methods
10
+ end
11
+ end
12
+
13
+ class Object
14
+ def clear_cache_method
15
+ instance_variables.each do |iv|
16
+ remove_instance_variable iv if iv =~ /^@cached_/
17
+ end
18
+ end
19
+ end
20
+
21
+ module DeclarativeCache
22
+ DISABLED = false
23
+
24
+ warn "CASHE DISABLED" if DISABLED
25
+ unless DISABLED
26
+ class << self
27
+
28
+ def cache_method klass, *methods
29
+ methods.each do |method|
30
+ klass.class_eval do
31
+ als = "cached_#{escape_method(method)}"
32
+ iv_check = "@#{als}_check"
33
+ iv = "@#{als}"
34
+
35
+ raise "Can't cache the #{method} twice!" if instance_methods.include?(als)
36
+
37
+ alias_method als, method
38
+
39
+ define_method method do |*args|
40
+ raise "You tried to use cache without params for method with params (use 'cache_method_with_params' instead)!" unless args.empty?
41
+ unless cached = instance_variable_get(iv)
42
+ unless check = instance_variable_get(iv_check)
43
+ cached = send als
44
+ instance_variable_set iv, cached
45
+ instance_variable_set iv_check, true
46
+ end
47
+ end
48
+ cached
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def cache_method_with_params klass, *methods
55
+ methods.each do |method|
56
+ klass.class_eval do
57
+ als = "cached_#{escape_method(method)}"
58
+ iv = "@#{als}"
59
+
60
+ raise "Can't cache the '#{method}' twice!" if instance_methods.include?(als)
61
+
62
+ alias_method als, method
63
+
64
+ define_method method do |*args|
65
+ unless results = instance_variable_get(iv)
66
+ results = Hash.new(NotDefined)
67
+ instance_variable_set iv, results
68
+ end
69
+
70
+ result = results[args]
71
+
72
+ if result.equal? NotDefined
73
+ result = send als, *args
74
+ results[args] = result
75
+ end
76
+
77
+ result
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,62 @@
1
+ class Object
2
+ def deep_clone
3
+ clone = self.clone
4
+ instance_variables.each do |name|
5
+ value = instance_variable_get name
6
+ clone.instance_variable_set name, value.deep_clone
7
+ end
8
+ clone
9
+ end
10
+ end
11
+
12
+ Hash.class_eval do
13
+ def deep_clone
14
+ clone = super
15
+ clone.clear
16
+ each{|k, v| clone[k.deep_clone] = v.deep_clone}
17
+ clone
18
+ end
19
+ end
20
+
21
+ OpenObject.class_eval do
22
+ def deep_clone
23
+ clone = super
24
+ clone.clear
25
+ each{|k, v| clone[k.deep_clone] = v.deep_clone}
26
+ clone
27
+ end
28
+ end
29
+
30
+ Struct.class_eval do
31
+ def deep_clone
32
+ clone = super
33
+ clone.clear
34
+ each_pair{|k, v| clone[k.deep_clone] = v.deep_clone}
35
+ clone
36
+ end
37
+ end
38
+
39
+ Array.class_eval do
40
+ def deep_clone
41
+ clone = super
42
+ clone.clear
43
+ each{|v| clone << v.deep_clone}
44
+ clone
45
+ end
46
+ end
47
+
48
+ [Class, Proc].each do |klass|
49
+ klass.class_eval do
50
+ def deep_clone
51
+ self
52
+ end
53
+ end
54
+ end
55
+
56
+ [Symbol, TrueClass, FalseClass, Numeric, TrueClass, FalseClass, NilClass].each do |klass|
57
+ klass.send :alias_method, :clone, :self
58
+ end
59
+
60
+ [String, Symbol, Range, Regexp, Time, Date].each do |klass|
61
+ klass.send :alias_method, :deep_clone, :clone
62
+ end
@@ -0,0 +1,16 @@
1
+ class ExtraBlankSlate
2
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
3
+
4
+ CUSTOM_UNDEFINE = [:p, :select, :puts]
5
+
6
+ undefine = Kernel.instance_methods + Object.instance_methods + CUSTOM_UNDEFINE
7
+ ExtraBlankSlate.instance_methods.each{|m| undefine.delete m}
8
+
9
+ undefine.each do |m|
10
+ script = %{\
11
+ def #{m} *p, &b
12
+ method_missing :#{m}, *p, &b
13
+ end}
14
+ class_eval script, __FILE__, __LINE__
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'fileutils'
2
+
3
+ File.class_eval do
4
+ class << self
5
+
6
+ def write(path, data)
7
+ File.open(path, "wb") do |file|
8
+ return file.write(data)
9
+ end
10
+ end
11
+
12
+ def create_directory dir
13
+ FileUtils.mkdir_p dir unless File.exist? dir
14
+ end
15
+
16
+ def delete_directory dir
17
+ FileUtils.rm_r dir, :force => true if File.exist? dir
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ class Hash
2
+ def subset keys = nil, &block
3
+ h = {}
4
+ if keys
5
+ self.each do |k, v|
6
+ h[k] = v if keys.include? k
7
+ end
8
+ else
9
+ self.each do |k, v|
10
+ h[k] = v if block.call k
11
+ end
12
+ end
13
+ h
14
+ end
15
+ end
@@ -0,0 +1,69 @@
1
+ Kernel.class_eval do
2
+ def respond_to sym, *args
3
+ return nil if not respond_to? sym
4
+ send sym, *args
5
+ end
6
+
7
+ # def _ &b
8
+ # raise "Block isn't provided!" unless b
9
+ # return b
10
+ # end
11
+
12
+ def singleton_class(&block)
13
+ if block_given?
14
+ (class << self; self; end).class_eval(&block)
15
+ self
16
+ else
17
+ (class << self; self; end)
18
+ end
19
+ end
20
+ alias_method :metaclass, :singleton_class
21
+ alias_method :metaclass_eval, :singleton_class
22
+
23
+ # Removes the namespace (exact match and underscored) of given class (or self) from stacktrace
24
+ def raise_without_self *args
25
+ error, message, klasses = nil
26
+ if args.size == 1
27
+ error = RuntimeError
28
+ message = args[0]
29
+ klasses = [self]
30
+ elsif args.size == 2
31
+ message, klasses = args
32
+ error = RuntimeError
33
+
34
+ klasses = Array(klasses)
35
+ klasses << self
36
+ elsif args.size == 3
37
+ error, message, klasses = args
38
+
39
+ klasses = Array(klasses)
40
+ klasses << self
41
+ else
42
+ raise RuntimeError, "Invalid arguments!", caller
43
+ end
44
+
45
+ klasses.collect!{|c| (c.class == Class or c.class == Module or c.class == String) ? c : c.class}
46
+
47
+ # obtaining the namespace of each class
48
+ klasses.collect! do |c|
49
+ if c.respond_to? :namespace
50
+ c = c.namespace while c.namespace
51
+ c
52
+ else
53
+ c
54
+ end
55
+ end
56
+
57
+ # building regexp
58
+ skip = []
59
+ klasses.each do |c|
60
+ skip.push(/\/#{c.to_s}/) # exact match
61
+ skip.push(/\/#{c.to_s.underscore}/) # underscored
62
+ end
63
+
64
+ # cleaning stacktrace
65
+ stack = caller.select{|path| !skip.any?{|re| re =~ path}}
66
+
67
+ raise error, message, stack
68
+ end
69
+ end
@@ -0,0 +1,14 @@
1
+ #
2
+ # string_or_symbol?
3
+ #
4
+ class Object
5
+ def string_or_symbol?; false end
6
+ end
7
+
8
+ class String
9
+ def string_or_symbol?; true end
10
+ end
11
+
12
+ class Symbol
13
+ def string_or_symbol?; true end
14
+ end
@@ -0,0 +1,119 @@
1
+ require 'set'
2
+
3
+ Module.class_eval do
4
+ def is?(base)
5
+ ancestors.include?(base)
6
+ end
7
+
8
+ def wrap_method( sym, prefix = "old_", &blk )
9
+ old_method = "#{prefix}_#{sym}".to_sym
10
+ alias_method old_method, sym
11
+ define_method(sym) do |*args|
12
+ instance_exec(old_method, *args, &blk)
13
+ end
14
+ end
15
+
16
+ def namespace
17
+ if @module_namespace_defined
18
+ @module_namespace
19
+ else
20
+ @module_namespace_defined = true
21
+ @module_namespace = Module.namespace_for name
22
+ end
23
+ end
24
+
25
+ def each_namespace &block
26
+ current = namespace
27
+ while current do
28
+ block.call current
29
+ current = current.namespace
30
+ end
31
+ end
32
+
33
+ def each_ancestor include_standard = false, &block
34
+ if include_standard
35
+ ancestors.each{|a| block.call a unless a == self}
36
+ else
37
+ exclude = [self, Object, Kernel]
38
+ ancestors.each do |a|
39
+ block.call a unless exclude.include? a
40
+ end
41
+ end
42
+ end
43
+
44
+ def self_ancestors_and_namespaces &b
45
+ b.call self
46
+ each_ancestor &b
47
+ each_namespace &b
48
+ end
49
+
50
+ def self.namespace_for class_name
51
+ list = class_name.split("::")
52
+ if list.size > 1
53
+ list.pop
54
+ return eval(list.join("::"), TOPLEVEL_BINDING, __FILE__, __LINE__)
55
+ else
56
+ return nil
57
+ end
58
+ end
59
+
60
+ def inheritable_accessor attribute_name, default_value
61
+ raise "Can be used only for Class and Module" unless self.class.is? Module
62
+ # raise "Default value can't be nil!" unless default_value
63
+
64
+ iv_name = "@#{attribute_name}"
65
+ iv_defined = "@#{attribute_name}_defined"
66
+
67
+ define_method attribute_name do
68
+ unless instance_variable_get(iv_defined)
69
+ iv = nil
70
+ ancestors[1..-1].each do |a|
71
+ if a.respond_to?(attribute_name) and (value = a.send(attribute_name))
72
+ iv = value.deep_clone
73
+ break
74
+ end
75
+ end
76
+ iv ||= default_value.deep_clone
77
+ instance_variable_set iv_name, iv
78
+ instance_variable_set iv_defined, true
79
+ iv
80
+ else
81
+ instance_variable_get iv_name
82
+ end
83
+ end
84
+
85
+ define_method "#{attribute_name}=" do |value|
86
+ # raise "Value can't be nil!" unless value
87
+ instance_variable_set iv_name, value
88
+ instance_variable_set iv_defined, true
89
+ end
90
+ end
91
+
92
+ raise "Internal error, it shouldn't be loaded twice!" if defined? ESCAPE_METHOD_SYMBOLS # some tricky error when runing spec with rake
93
+ ESCAPE_METHOD_SYMBOLS = [
94
+ ['==', 'assign'],
95
+ ['>', 'gt'],
96
+ ['<', 'lt'],
97
+ ['>=', 'gte'],
98
+ ['<=', 'lte'],
99
+ ['?', 'qst'],
100
+ ['!', 'imp'],
101
+ ['<=>', 'lorg'],
102
+ ['*', 'mp'],
103
+ ['+', 'add'],
104
+ ['-', 'sub'],
105
+ ['=', 'assign'],
106
+ ['**', 'pw'],
107
+ ['=~', 'sim'],
108
+ ['[]', 'sb'],
109
+ ]
110
+
111
+ def escape_method method
112
+ m = method.to_s.clone
113
+ ESCAPE_METHOD_SYMBOLS.each{|from, to| m.gsub! from, to}
114
+ raise "Invalid method name '#{method}'!" unless m =~ /^[_a-zA-Z0-9]+$/
115
+ m
116
+ end
117
+
118
+ public :include
119
+ end
@@ -0,0 +1,76 @@
1
+ #
2
+ # Fix for ruby's broken include.
3
+ # Included modules doesn't propagated to it's children.
4
+ #
5
+ # Test case:
6
+ # module A; end
7
+ # module B
8
+ # include A
9
+ # end
10
+ #
11
+ # module Plugin; end
12
+ # A.send(:include, Plugin)
13
+ #
14
+ # p "Ancestors of A: " + A.ancestors.join(', ') # => "Ancestors of A: A, Plugin"
15
+ # p "Ancestors of B: " + B.ancestors.join(', ') # => "Ancestors of B: B, A" << NO PLUGIN!
16
+ #
17
+ class Module
18
+ def directly_included_by
19
+ @directly_included_by ||= Set.new
20
+ end
21
+
22
+ def fixed_include mod
23
+ unless mod.directly_included_by.include? self
24
+ mod.directly_included_by.add self
25
+ end
26
+
27
+ include mod
28
+ directly_included_by.each do |child|
29
+ child.fixed_include self
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+ #
36
+ # Inheritance
37
+ #
38
+ class Module
39
+ def class_prototype
40
+ unless @class_prototype
41
+ unless const_defined? :ClassMethods
42
+ class_eval "module ClassMethods; end", __FILE__, __LINE__
43
+ end
44
+ @class_prototype = const_get :ClassMethods
45
+
46
+ (class << self; self end).fixed_include @class_prototype
47
+ end
48
+ @class_prototype
49
+ end
50
+
51
+ def class_methods &block
52
+ if block
53
+ class_prototype.class_eval &block
54
+ extend class_prototype
55
+ else
56
+ class_prototype.instance_methods
57
+ end
58
+ end
59
+
60
+ def inherit *modules
61
+ modules.each do |mod|
62
+ # Instance Methods
63
+ fixed_include mod
64
+
65
+ # Class Methods
66
+ if self.class == Module
67
+ class_prototype.fixed_include mod.class_prototype
68
+ else
69
+ (class << self; self end).fixed_include mod.class_prototype
70
+ end
71
+
72
+ # callback
73
+ mod.inherited self if mod.respond_to? :inherited
74
+ end
75
+ end
76
+ end