ruby_ext 0.4.6

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.
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