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
@@ -0,0 +1,166 @@
1
+ class AssertionError < StandardError; end
2
+
3
+ Object.class_eval do
4
+ def should_be! method
5
+ unless self.send("#{method}?") == true
6
+ raise AssertionError, "
7
+ ASSERTION FAILED (#{caller[0]}):
8
+ #{self.inspect} should be #{method}
9
+ ", caller
10
+ end
11
+
12
+ return self
13
+ end
14
+ alias_method :should_have!, :should_be!
15
+
16
+ def should_not_be! method
17
+ unless self.send("#{method}?") == false
18
+ raise AssertionError, "
19
+ ASSERTION FAILED (#{caller[0]}):
20
+ #{self.inspect} should not be #{method}
21
+ ", caller
22
+ end
23
+
24
+ return self
25
+ end
26
+ alias_method :should_not_have!, :should_not_be!
27
+
28
+ def should! cmd, arg = NotDefined
29
+ result = case cmd
30
+ when :be_never_called then
31
+ false
32
+
33
+ when :be_nil then
34
+ self.equal? nil
35
+
36
+ when :be_a
37
+ if arg.class == Array
38
+ arg.any?{|klass| self.is_a? klass}
39
+ else
40
+ self.is_a? arg
41
+ end
42
+
43
+ when :be_an
44
+ if arg.class == Array
45
+ arg.any?{|klass| self.is_a? klass}
46
+ else
47
+ self.is_a? arg
48
+ end
49
+
50
+ when :be
51
+ if arg.class == Array
52
+ arg.any?{|klass| self.respond_to :is?, klass}
53
+ else
54
+ self.respond_to :is?, arg
55
+ end
56
+
57
+ when :include then
58
+ self.include? arg
59
+
60
+ when :be_in then
61
+ arg.include? self
62
+
63
+ when :be_true then
64
+ self
65
+
66
+ when :be_false then
67
+ !self
68
+
69
+ when :be_empty then
70
+ self.empty?
71
+
72
+ else
73
+ if arg.equal? NotDefined
74
+ self.send cmd
75
+ else
76
+ self.send cmd, arg
77
+ end
78
+ end
79
+
80
+ unless result
81
+ unless arg.equal? NotDefined
82
+ raise AssertionError, "
83
+ ASSERTION FAILED (#{caller[0]}):
84
+ #{self.inspect} should #{cmd} #{arg.inspect}
85
+ ", caller
86
+ else
87
+ raise AssertionError, "
88
+ ASSERTION FAILED (#{caller[0]}):
89
+ #{self.inspect} should #{cmd}
90
+ ", caller
91
+ end
92
+ end
93
+
94
+ return self
95
+ end
96
+
97
+ def should_not! cmd, arg = NotDefined
98
+ result =
99
+ case cmd
100
+ when :be_never_called then
101
+ false
102
+
103
+ when :be_nil then
104
+ self.equal? nil
105
+
106
+ when :be_a
107
+ if arg.class == Array
108
+ arg.any?{|klass| self.is_a? klass}
109
+ else
110
+ self.is_a? arg
111
+ end
112
+
113
+ when :be_an
114
+ if arg.class == Array
115
+ arg.any?{|klass| self.is_a? klass}
116
+ else
117
+ self.is_a? arg
118
+ end
119
+
120
+ when :be
121
+ if arg.class == Array
122
+ arg.any?{|klass| self.respond_to :is?, klass}
123
+ else
124
+ self.respond_to :is?, arg
125
+ end
126
+
127
+ when :include then
128
+ self.include? arg
129
+
130
+ when :be_in then
131
+ arg.include? self
132
+
133
+ when :be_true then
134
+ self
135
+
136
+ when :be_false then
137
+ !self
138
+
139
+ when :be_empty then
140
+ self.empty?
141
+
142
+ else
143
+ if arg.equal? NotDefined
144
+ self.send cmd
145
+ else
146
+ self.send cmd, arg
147
+ end
148
+ end
149
+
150
+ if result
151
+ unless arg.equal? NotDefined
152
+ raise AssertionError, "
153
+ ASSERTION FAILED (#{caller[0]}):
154
+ #{self.inspect} should not #{cmd} #{arg.inspect}
155
+ ", caller
156
+ else
157
+ raise AssertionError, "
158
+ ASSERTION FAILED (#{caller[0]}):
159
+ #{self.inspect} should not #{cmd}
160
+ ", caller
161
+ end
162
+ end
163
+
164
+ return self
165
+ end
166
+ end
@@ -0,0 +1,44 @@
1
+ String.class_eval do
2
+ def dirname
3
+ File.expand_path(File.dirname(self))
4
+ end
5
+
6
+ def parent_dirname
7
+ File.expand_path(File.dirname(self) + "/..")
8
+ end
9
+
10
+ def to_reader
11
+ self.to_sym
12
+ end
13
+
14
+ def to_writer
15
+ "#{self}=".to_sym
16
+ end
17
+
18
+ def to_iv
19
+ "@#{self}"
20
+ end
21
+
22
+ def interpolate binding
23
+ binding.must_be.a Binding
24
+ return gsub(/\#\{.+?\}/) do |term|
25
+ identifier = term.slice(2 .. term.size-2)
26
+ binding.eval identifier
27
+ end
28
+ end
29
+
30
+ def self.secure_token
31
+ original = [Time.now, (1..10).map{ rand.to_s }]
32
+ Digest::SHA1.hexdigest(original.flatten.join('--'))
33
+ end
34
+
35
+ def underscore
36
+ word = self.dup
37
+ word.gsub!(/::/, '/')
38
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
39
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
40
+ word.tr!("-", "_")
41
+ word.downcase!
42
+ word
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ Symbol.class_eval do
2
+ def <=> other
3
+ self.to_s <=> other.to_s
4
+ end
5
+
6
+ def to_reader
7
+ self
8
+ end
9
+
10
+ def to_writer
11
+ "#{self}=".to_sym
12
+ end
13
+
14
+ def to_iv
15
+ "@#{self}"
16
+ end
17
+
18
+ def + other
19
+ (self.to_s + other.to_s).to_sym
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'monitor'
2
+
3
+ class Module
4
+ def synchronize_method *methods
5
+ methods.each do |method|
6
+ als = "sync_#{escape_method(method)}"
7
+
8
+ raise "Can't synchronize the '#{method}' twice!" if instance_methods.include?(als)
9
+
10
+ alias_method als, method
11
+ script = "\
12
+ def #{method} *p, &b
13
+ @monitor ||= Monitor.new
14
+ @monitor.synchronize{#{als} *p, &b}
15
+ end"
16
+ class_eval script, __FILE__, __LINE__
17
+ end
18
+ end
19
+
20
+ def synchronize_all_methods include_super = false
21
+ methods = self.instance_methods(include_super).collect{|m| m.to_sym}
22
+ synchronize_method *methods
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ class Tuple
2
+ attr_accessor :first, :last
3
+
4
+ def initialize first = nil, last = nil
5
+ @first, @last = first, last
6
+ end
7
+ end
data/lib/ruby_ext.rb ADDED
@@ -0,0 +1,50 @@
1
+ core = [
2
+ 'facets/array/indexable', # Array first!, last!
3
+ 'facets/enumerable/every',
4
+ 'facets/enumerable/group_by',
5
+ 'facets/exception/detail', # pretty print
6
+ 'facets/duplicable', # false.dup(), false.clone() and so on.
7
+ 'facets/blank',
8
+ 'facets/numeric/round.rb', # round_at, round_to
9
+ 'facets/hash',
10
+ 'facets/string/interpolate',
11
+ # 'facets/ostruct',
12
+ # 'facets/openobject' it has broken implementation and is completelly rewritend in ruby-ext
13
+ ]
14
+
15
+ more = [
16
+ # 'facets/basicobject', causes problem with rspec
17
+ # 'facets/opencascade', causes problem with redefined OpenObject
18
+ ]
19
+
20
+ (core + more).each{|f| require f}
21
+
22
+ {
23
+ :BasicObject => 'basic_object',
24
+ :OpenObject => 'open_object',
25
+ :OpenConstructor => 'open_constructor',
26
+ :Observable2 => 'observable2',
27
+ :ExtraBlankSlate => 'extra_blank_slate', # do I need it?
28
+ :Tuple => 'tuple',
29
+ }.each{|klass, file| Kernel.autoload klass, "ruby_ext/#{file}"}
30
+
31
+ %w{
32
+ file
33
+ array
34
+ hash
35
+ kernel
36
+ module
37
+ not_defined
38
+ object
39
+ class
40
+ string
41
+ symbol
42
+
43
+ deep_clone
44
+ declarative_cache
45
+ must
46
+ prepare_arguments
47
+ synchronize
48
+ micelaneous
49
+ multiple_inheritance
50
+ }.each{|f| require "ruby_ext/#{f}"}
data/lib/spec_ext.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'spec'
2
+
3
+ Spec::Example::ExampleGroup.class_eval do
4
+ def remove_constants *args
5
+ args = args.first if args.size == 1 and args.first.is_a?(Array)
6
+ # args.each{|c| raise "Invalid constant name '#{c}'!" unless c =~ /^[a-z_][a-z_0-9]*$/i}
7
+ # args = args.first if args.first.is_a?(Array)
8
+ args.each{|c| Object.send :remove_const, c if Object.const_defined? c}
9
+ end
10
+ end
data/readme.md ADDED
@@ -0,0 +1,66 @@
1
+ # Ruby extensions
2
+ **ruby-ext** is a collection of various utility classes and standard library extensions for the Ruby language.
3
+
4
+ ## must - assertion tool, kind of RSpec assertions in runtime code
5
+
6
+ 1.must_be.in 1..2
7
+ "a".must_be.in 'a', 'b', 'c'
8
+ key.must_be.a String
9
+ value.must_not_be.nil
10
+ must_be.never_called
11
+ a.must_be == b
12
+
13
+ ## inherit - combines include & extend in one
14
+ Do you remember this *def self.included(base) ... end* hack? You don't need it anymore.
15
+
16
+ module Feature
17
+ def cool_method; end
18
+ class_methods do
19
+ def cool_class_method; end
20
+ end
21
+ end
22
+
23
+ class TheClass
24
+ inherit Feature
25
+ end
26
+
27
+ TheClass.new.cool_method
28
+ TheClass.cool_class_method
29
+
30
+ ## cache_method & synchronize_method
31
+
32
+ def complex_calculation
33
+ 2 * 2
34
+ end
35
+ cache_method :complex_calculation
36
+
37
+ def money_transfer amount
38
+ @from -= amount
39
+ @to += amount
40
+ end
41
+ synchronize_method :money_transfer
42
+
43
+ ## OpenConstructor - adds mass assignment to any class
44
+
45
+ class TheClass
46
+ include OpenConstructor
47
+ attr_accessor :a, :b
48
+ end
49
+
50
+ o = TheClass.new.set :a => 'a', :b => 'b'
51
+ o.a => 'a'
52
+ o.to_hash => {:a => 'a', :b => 'b'}
53
+
54
+ ## More
55
+
56
+ These are just a small part of all handy methods and extensions, for more details please go to specs.
57
+
58
+ # Usage
59
+
60
+ $ sudo gem install ruby-ext
61
+
62
+ require 'ruby_ext'
63
+
64
+ Copyright (c) 2009 Alexey Petrushin [http://bos-tec.com](http://bos-tec.com), released under the MIT license.
65
+
66
+ [ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
@@ -0,0 +1,190 @@
1
+ require "#{File.dirname __FILE__}/helper"
2
+ require "ruby_ext/prototype_inheritance"
3
+
4
+ describe "Prototype Inheritance" do
5
+ after :each do
6
+ remove_constants %w(A B C)
7
+ end
8
+
9
+ it "should define and override methods" do
10
+ class A
11
+ instance_methods do
12
+ def instance_method
13
+ 'first version'
14
+ end
15
+ end
16
+ class_methods do
17
+ def class_method
18
+ 'first version'
19
+ end
20
+ end
21
+ end
22
+
23
+ A.new.instance_method.should == "first version"
24
+ A.class_method.should == "first version"
25
+
26
+
27
+ A.instance_methods do
28
+ def instance_method
29
+ 'second version'
30
+ end
31
+ end
32
+
33
+ A.class_methods do
34
+ def class_method
35
+ 'second version'
36
+ end
37
+ end
38
+
39
+ A.new.instance_method.should == "second version"
40
+ A.class_method.should == "second version"
41
+ end
42
+
43
+ it "showcase" do
44
+ class A
45
+ instance_methods do
46
+ def a; end
47
+
48
+ def overrided_method
49
+ 'a version'
50
+ end
51
+ end
52
+
53
+ class_methods do
54
+ def class_a; end
55
+ end
56
+
57
+ def self.inherited target
58
+ target.prototype.send :attr_accessor, :some_accessor
59
+ end
60
+ end
61
+
62
+ class B
63
+ instance_methods do
64
+ def b; end
65
+
66
+ def overrided_method
67
+ 'b version'
68
+ end
69
+ end
70
+
71
+ class_methods do
72
+ def class_b; end
73
+ end
74
+ end
75
+
76
+ class C
77
+ inherit A, B
78
+ end
79
+
80
+ c = C.new
81
+ c.should respond_to(:a)
82
+ c.should respond_to(:b)
83
+ c.should respond_to(:some_accessor)
84
+
85
+ C.should respond_to(:class_a)
86
+ C.should respond_to(:class_b)
87
+ end
88
+
89
+ it "should inherit all ancestors class methods (and take order into account by overriding)" do
90
+ class A
91
+ instance_methods do
92
+ def a; end
93
+
94
+ def overrided
95
+ 'a'
96
+ end
97
+ end
98
+
99
+ class_methods do
100
+ def class_a; end
101
+ end
102
+ end
103
+
104
+ class B
105
+ inherit A
106
+
107
+ instance_methods do
108
+ def b; end
109
+
110
+ def overrided
111
+ 'b'
112
+ end
113
+ end
114
+
115
+ class_methods do
116
+ def class_b; end
117
+ end
118
+ end
119
+
120
+ class C
121
+ inherit B
122
+ end
123
+
124
+ c = C.new
125
+ c.should respond_to(:a)
126
+ c.should respond_to(:b)
127
+ c.overrided.should == 'b'
128
+
129
+ C.should respond_to(:class_a)
130
+ C.should respond_to(:class_b)
131
+
132
+ C.instance_methods do
133
+ def overrided
134
+ 'c'
135
+ end
136
+ end
137
+ c = C.new
138
+ c.overrided.should == 'c'
139
+ end
140
+
141
+ it "shouldn't redefine ancestors class methods (from error)" do
142
+ class A
143
+ class_methods do
144
+ def class_method; end
145
+ end
146
+ end
147
+
148
+ class B
149
+ inherit A
150
+
151
+ class_methods do
152
+ def class_method2; end
153
+ end
154
+ end
155
+
156
+ A.should_not respond_to(:class_method2)
157
+ end
158
+
159
+ it "methods defined on base class after inheritance must be propagated to all descendants" do
160
+ class A; end
161
+
162
+ class B
163
+ inherit A
164
+ end
165
+
166
+ B.instance_methods.should_not include('method_added_after_inheritance')
167
+ A.prototype.send(:define_method, :method_added_after_inheritance){}
168
+ A.instance_methods.should include('method_added_after_inheritance')
169
+ B.instance_methods.should include('method_added_after_inheritance')
170
+ end
171
+
172
+ it "classes included in base class after inheritance must be propagated to all descendants" do
173
+ class A; end
174
+
175
+ class B
176
+ inherit A
177
+ end
178
+
179
+ class C
180
+ instance_methods do
181
+ def module_added_after_inheritance; end
182
+ end
183
+ end
184
+
185
+ A.instance_methods.should_not include('module_added_after_inheritance')
186
+ A.inherit C
187
+ A.instance_methods.should include('module_added_after_inheritance')
188
+ B.instance_methods.should include('module_added_after_inheritance')
189
+ end
190
+ end
@@ -0,0 +1,8 @@
1
+ require "#{File.dirname __FILE__}/helper"
2
+ require "ruby_ext/array"
3
+
4
+ describe 'Array' do
5
+ it 'sfilter' do
6
+ %w{alfa betta gamma}.sfilter('lfa', /et/).should == ['gamma']
7
+ end
8
+ end
@@ -0,0 +1,115 @@
1
+ require "#{File.dirname __FILE__}/helper"
2
+ require "ruby_ext/declarative_cache"
3
+
4
+ describe 'DeclarativeCache' do
5
+ class CachedClass
6
+ attr_accessor :value
7
+ def value_get; @value end
8
+ cache_method :value_get
9
+
10
+ attr_accessor :value2
11
+ def value2_get; @value2 end
12
+
13
+ attr_accessor :params
14
+ def params_get param; @params[param] end
15
+
16
+ attr_accessor :multiplier
17
+ def *(arg)
18
+ @multiplier * arg
19
+ end
20
+ cache_method_with_params '*'
21
+ end
22
+
23
+ DeclarativeCache.cache_method CachedClass, :value2_get
24
+ DeclarativeCache.cache_method_with_params CachedClass, :params_get
25
+
26
+ it "Simple Cache" do
27
+ o = CachedClass.new
28
+ o.value = 0
29
+ o.value2 = 0
30
+ o.value_get.should == 0
31
+ o.value2_get.should == 0
32
+
33
+ o.value = 1
34
+ o.value2 = 1
35
+ o.value_get.should == 0
36
+ o.value2_get.should == 0
37
+ end
38
+
39
+ it "clear_cache_method" do
40
+ o = CachedClass.new
41
+ o.value = 0
42
+ o.value_get.should == 0
43
+
44
+ o.value = 1
45
+ o.value_get.should == 0
46
+
47
+ o.clear_cache_method
48
+ o.value_get.should == 1
49
+ end
50
+
51
+ it "should check for parameters" do
52
+ o = CachedClass.new
53
+ lambda{o.value_get(1)}.should raise_error(/cache_method_with_params/)
54
+ end
55
+
56
+ it "Cache With Params" do
57
+ o = CachedClass.new
58
+ o.params = {:a => :b}
59
+ o.params_get(:a).should == :b
60
+ o.params = {:a => :c}
61
+ o.params_get(:a).should == :b
62
+ end
63
+
64
+ it "should works with operators" do
65
+ o = CachedClass.new
66
+ o.multiplier = 2
67
+ (o * 2).should == 4
68
+ o.multiplier = 3
69
+ (o * 2).should == 4
70
+ end
71
+
72
+ class CachedClass2
73
+ class << self
74
+ attr_accessor :value
75
+ def value_get; @value end
76
+ cache_method :value_get
77
+ end
78
+ end
79
+
80
+ it "Simple Cache" do
81
+ CachedClass2.value = 0
82
+ CachedClass2.value_get.should == 0
83
+ CachedClass2.value = 1
84
+ CachedClass2.value_get.should == 0
85
+ end
86
+
87
+ module CachedModule
88
+ attr_accessor :value
89
+ def value_get; @value end
90
+ cache_method :value_get
91
+ end
92
+
93
+ class CachedClass3
94
+ include CachedModule
95
+ end
96
+
97
+ it "should also works with modules (from error)" do
98
+ o = CachedClass.new
99
+ o.value = 0
100
+ o.value_get.should == 0
101
+
102
+ o.value = 1
103
+ o.value_get.should == 0
104
+ end
105
+
106
+ class CachedClass4
107
+ attr_accessor :value
108
+ def value_get; @value end
109
+ end
110
+
111
+ it "should not allow to cache twice" do
112
+ CachedClass4.cache_method :value_get
113
+ lambda{CachedClass4.cache_method :value_get}.should raise_error(/twice/)
114
+ end
115
+ end