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