ruby_ext 0.4.11 → 0.4.12
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +6 -6
- data/lib/rake_ext.rb +10 -5
- data/lib/rake_ext/project.rb +31 -16
- data/lib/rspec_ext.rb +82 -19
- data/lib/ruby_ext.rb +1 -52
- data/lib/ruby_ext/core.rb +24 -0
- data/lib/ruby_ext/{array.rb → core/array.rb} +4 -2
- data/lib/ruby_ext/core/basic_object.rb +8 -0
- data/lib/ruby_ext/core/class.rb +0 -0
- data/lib/ruby_ext/{deep_clone.rb → core/deep_clone.rb} +3 -4
- data/lib/ruby_ext/core/enumerable.rb +17 -0
- data/lib/ruby_ext/{file.rb → core/file.rb} +5 -2
- data/lib/ruby_ext/core/hash.rb +23 -0
- data/lib/ruby_ext/{kernel.rb → core/kernel.rb} +0 -0
- data/lib/ruby_ext/{micelaneous.rb → core/micelaneous.rb} +0 -0
- data/lib/ruby_ext/{module.rb → core/module.rb} +13 -2
- data/lib/ruby_ext/{multiple_inheritance.rb → core/multiple_inheritance.rb} +30 -14
- data/lib/ruby_ext/{must.rb → core/must.rb} +30 -27
- data/lib/ruby_ext/{not_defined.rb → core/not_defined.rb} +0 -0
- data/lib/ruby_ext/{object.rb → core/object.rb} +0 -0
- data/lib/ruby_ext/{open_object.rb → core/open_object.rb} +21 -16
- data/lib/ruby_ext/{string.rb → core/string.rb} +27 -0
- data/lib/ruby_ext/{symbol.rb → core/symbol.rb} +0 -0
- data/lib/ruby_ext/fixes.rb +6 -0
- data/lib/ruby_ext/gems.rb +0 -1
- data/lib/ruby_ext/more.rb +11 -0
- data/lib/ruby_ext/more/declarative_cache.rb +96 -0
- data/lib/ruby_ext/more/micelaneous.rb +7 -0
- data/lib/ruby_ext/{observable2.rb → more/observable2.rb} +0 -0
- data/lib/ruby_ext/{open_constructor.rb → more/open_constructor.rb} +2 -2
- data/lib/ruby_ext/more/safe_hash.rb +214 -0
- data/lib/ruby_ext/{synchronize.rb → more/synchronize.rb} +5 -5
- data/lib/ruby_ext/{tuple.rb → more/tuple.rb} +0 -0
- data/lib/yaml_fix.rb +9 -0
- data/readme.md +46 -42
- data/spec/core/array_spec.rb +7 -0
- data/spec/{deep_clone_spec.rb → core/deep_clone_spec.rb} +2 -3
- data/spec/core/enumerable.rb +9 -0
- data/spec/{kernel_spec.rb → core/kernel_spec.rb} +4 -6
- data/spec/{kernel_spec → core/kernel_spec}/TheNamespace/ClassA.rb +0 -0
- data/spec/{kernel_spec → core/kernel_spec}/another_class.rb +0 -0
- data/spec/{kernel_spec → core/kernel_spec}/the_namespace/class_b.rb +0 -0
- data/spec/{module_spec.rb → core/module_spec.rb} +2 -4
- data/spec/{multiple_inheritance_spec.rb → core/multiple_inheritance_spec.rb} +28 -12
- data/spec/core/must_spec.rb +32 -0
- data/spec/{open_object_spec.rb → core/open_object_spec.rb} +6 -7
- data/spec/core/spec_helper.rb +2 -0
- data/spec/{declarative_cache_spec.rb → more/declarative_cache_spec.rb} +35 -8
- data/spec/{observable2_spec.rb → more/observable2_spec.rb} +3 -4
- data/spec/{open_constructor_spec.rb → more/open_constructor_spec.rb} +6 -7
- data/spec/more/safe_hash_spec.rb +133 -0
- data/spec/more/spec_helper.rb +2 -0
- data/spec/{synchronize_spec.rb → more/synchronize_spec.rb} +2 -3
- metadata +67 -100
- data/lib/ruby_ext/basic_object.rb +0 -22
- data/lib/ruby_ext/class.rb +0 -11
- data/lib/ruby_ext/declarative_cache.rb +0 -85
- data/lib/ruby_ext/extra_blank_slate.rb +0 -17
- data/lib/ruby_ext/hash.rb +0 -15
- data/lib/ruby_ext/prepare_arguments.rb +0 -105
- data/lib/ruby_ext/prototype_inheritance.rb +0 -110
- data/lib/ruby_ext/should.rb +0 -166
- data/lib/rubyopt.rb +0 -7
- data/spec/_prototype_inheritance_spec.rb +0 -190
- data/spec/array_spec.rb +0 -8
- data/spec/must_spec.rb +0 -29
- data/spec/prepare_arguments_spec.rb +0 -46
- data/spec/should_spec.rb +0 -24
- data/spec/spec_helper.rb +0 -19
data/lib/ruby_ext/gems.rb
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
gem 'facets', '2.9.0'
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
Module.class_eval do
|
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
|
15
|
+
instance_variables.each do |iv|
|
16
|
+
remove_instance_variable iv if iv =~ /_cache$/ or iv =~ /_cache_check$/
|
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
|
+
escaped_method = escape_method(method)
|
32
|
+
method_with_cache, method_without_cache = "#{escaped_method}_with_cache".to_sym, "#{escaped_method}_without_cache".to_sym
|
33
|
+
iv_check = "@#{escaped_method}_cache_check"
|
34
|
+
iv = "@#{escaped_method}_cache"
|
35
|
+
|
36
|
+
if instance_methods.include?(method_with_cache) or instance_methods.include?(method_without_cache)
|
37
|
+
warn "can't cache the :#{method} twice!"
|
38
|
+
else
|
39
|
+
alias_method method_without_cache, method
|
40
|
+
|
41
|
+
define_method method_with_cache do |*args|
|
42
|
+
raise "You tried to use cache without params for method with params (use 'cache_method_with_params' instead)!" unless args.empty?
|
43
|
+
unless cached = instance_variable_get(iv)
|
44
|
+
unless check = instance_variable_get(iv_check)
|
45
|
+
cached = send method_without_cache
|
46
|
+
instance_variable_set iv, cached
|
47
|
+
instance_variable_set iv_check, true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
cached
|
51
|
+
end
|
52
|
+
|
53
|
+
alias_method method, method_with_cache
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache_method_with_params klass, *methods
|
60
|
+
methods.each do |method|
|
61
|
+
klass.class_eval do
|
62
|
+
escaped_method = escape_method(method)
|
63
|
+
method_with_cache, method_without_cache = "#{escaped_method}_with_cache".to_sym, "#{escaped_method}_without_cache".to_sym
|
64
|
+
iv_check = "@#{escaped_method}_cache_check"
|
65
|
+
iv = "@#{escaped_method}_cache"
|
66
|
+
|
67
|
+
if instance_methods.include?(method_with_cache) or instance_methods.include?(method_without_cache)
|
68
|
+
warn "can't cache the :#{method} twice!"
|
69
|
+
else
|
70
|
+
alias_method method_without_cache, method
|
71
|
+
|
72
|
+
define_method method_with_cache do |*args|
|
73
|
+
unless results = instance_variable_get(iv)
|
74
|
+
results = Hash.new(NotDefined)
|
75
|
+
instance_variable_set iv, results
|
76
|
+
end
|
77
|
+
|
78
|
+
result = results[args]
|
79
|
+
|
80
|
+
if result.equal? NotDefined
|
81
|
+
result = send method_without_cache, *args
|
82
|
+
results[args] = result
|
83
|
+
end
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
alias_method method, method_with_cache
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
File without changes
|
@@ -33,13 +33,13 @@ module OpenConstructor
|
|
33
33
|
return self
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
36
|
+
def set! values
|
37
37
|
values.each do |k, v|
|
38
38
|
self.send k.to_writer, v
|
39
39
|
end
|
40
40
|
return self
|
41
41
|
end
|
42
|
-
alias_method :set
|
42
|
+
# alias_method :set! #, :set_with_check
|
43
43
|
|
44
44
|
def to_hash
|
45
45
|
hash = {}
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# require 'singleton'
|
2
|
+
|
3
|
+
class SafeHash < BasicObject
|
4
|
+
attr_reader :hash
|
5
|
+
|
6
|
+
alias_method :send, :__send__
|
7
|
+
|
8
|
+
def initialize hash = {}
|
9
|
+
reinitialize hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def []= key, value
|
13
|
+
::SafeHash.forbidden! key
|
14
|
+
# value = ::SafeHash.new value if value.is_a? ::Hash
|
15
|
+
# @hash[key.to_sym] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def set! key, value
|
19
|
+
value = ::SafeHash.new value if value.is_a? ::Hash
|
20
|
+
@hash[key.to_sym] = value
|
21
|
+
end
|
22
|
+
def set *args; raise "you probably mistyped :set! method!" end
|
23
|
+
|
24
|
+
def include? key
|
25
|
+
@hash.include? key.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
def tap &b
|
29
|
+
b.call self
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def [] key, if_not_exist = ::NotDefined
|
34
|
+
last = key[-1]
|
35
|
+
if last == '!'
|
36
|
+
key = key[0..-2].to_sym
|
37
|
+
if @hash.include? key
|
38
|
+
@hash[key]
|
39
|
+
else
|
40
|
+
raise "no key :#{key}"
|
41
|
+
end
|
42
|
+
elsif last == '?'
|
43
|
+
key = key[0..-2].to_sym
|
44
|
+
@hash.include? key
|
45
|
+
else
|
46
|
+
key = key.to_sym
|
47
|
+
if @hash.include? key
|
48
|
+
@hash[key]
|
49
|
+
elsif if_not_exist == ::NotDefined
|
50
|
+
SafeNil.new key
|
51
|
+
else
|
52
|
+
return if_not_exist
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def reinitialize hash
|
58
|
+
@hash = {}
|
59
|
+
merge! hash
|
60
|
+
# hash.each do |k, v|
|
61
|
+
# v = ::SafeHash.new v if v.is_a? ::Hash
|
62
|
+
# @hash[k.to_sym] = v
|
63
|
+
# end
|
64
|
+
# @hash.freeze
|
65
|
+
end
|
66
|
+
|
67
|
+
def method_missing m, obj = ::NotDefined, &b
|
68
|
+
raise "invalid usage, can't pass block to (:#{m})!" if b
|
69
|
+
last = m[-1]
|
70
|
+
if last == '='
|
71
|
+
::SafeHash.forbidden! m[0..-2]
|
72
|
+
# self[m[0..-2]] = obj
|
73
|
+
else
|
74
|
+
self[m, obj]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_yaml *args
|
79
|
+
@hash.to_yaml *args
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
@hash.inspect
|
84
|
+
end
|
85
|
+
|
86
|
+
def delete key
|
87
|
+
@hash.delete key.to_sym
|
88
|
+
end
|
89
|
+
|
90
|
+
def merge! hash, options = {}
|
91
|
+
# parsing arguments
|
92
|
+
deep = options[:deep] || true
|
93
|
+
override = options[:override] || false
|
94
|
+
blank = options[:blank] || false
|
95
|
+
options.validate_options! :deep, :override, :blank
|
96
|
+
raise "invalid options, can't do both :blank and :override simultaneously!" if blank and override
|
97
|
+
|
98
|
+
# merging
|
99
|
+
hash.each do |k, v|
|
100
|
+
k = k.to_sym
|
101
|
+
if @hash.include? k
|
102
|
+
if deep and (old_v = @hash[k]).respond_to(:is_a_safe_hash?) and v.is_a?(::Hash)
|
103
|
+
old_v.merge! v, options
|
104
|
+
else
|
105
|
+
if blank
|
106
|
+
# do nothing
|
107
|
+
elsif override
|
108
|
+
self.set! k, v
|
109
|
+
else
|
110
|
+
raise "can't override :#{k} config value!" unless override
|
111
|
+
end
|
112
|
+
end
|
113
|
+
else
|
114
|
+
self.set! k, v
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def merge *args; raise "you probably mistyped :merge! method!" end
|
119
|
+
|
120
|
+
def merge_if_blank! hash, options = {}
|
121
|
+
options[:blank] = true
|
122
|
+
merge! hash, options
|
123
|
+
end
|
124
|
+
def merge_if_blank *args; raise "you probably mistyped :merge_if_blank method!" end
|
125
|
+
|
126
|
+
# deep conversion, check and converts nested SafeHashes to Hashes
|
127
|
+
def to_hash options = {}
|
128
|
+
r = {}
|
129
|
+
@hash.each do |k, v|
|
130
|
+
k = k.to_s if options[:to_s]
|
131
|
+
r[k] = if v.respond_to :is_a_safe_hash?
|
132
|
+
v.to_hash options
|
133
|
+
else
|
134
|
+
v
|
135
|
+
end
|
136
|
+
end
|
137
|
+
r
|
138
|
+
end
|
139
|
+
alias_method :to_h, :to_hash
|
140
|
+
|
141
|
+
def is_a_safe_hash?
|
142
|
+
true
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
class SafeNil < BasicObject
|
147
|
+
# include ::Singleton
|
148
|
+
|
149
|
+
def initialize key
|
150
|
+
@key = key
|
151
|
+
end
|
152
|
+
|
153
|
+
def [] key, if_not_exist = ::NotDefined
|
154
|
+
last = key[-1]
|
155
|
+
if last == '!'
|
156
|
+
raise "no key :#{key}"
|
157
|
+
elsif last == '?'
|
158
|
+
false
|
159
|
+
elsif if_not_exist == ::NotDefined
|
160
|
+
SafeNil.new key
|
161
|
+
else
|
162
|
+
return if_not_exist
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def method_missing m, if_not_exist = ::NotDefined, &b
|
167
|
+
raise "invalid usage, can't pass block to (:#{m})!" if b
|
168
|
+
last = m[-1]
|
169
|
+
if last == '='
|
170
|
+
::SafeHash.forbidden! m[0..-2]
|
171
|
+
# raise "No key '#{@key}'!"
|
172
|
+
else
|
173
|
+
self[m, if_not_exist]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def include? key
|
178
|
+
false
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_b
|
182
|
+
false
|
183
|
+
end
|
184
|
+
|
185
|
+
def to_yaml *args
|
186
|
+
nil.to_yaml *args
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_h
|
190
|
+
{}
|
191
|
+
end
|
192
|
+
|
193
|
+
def to_s
|
194
|
+
raise "can't convert SafeNil for key '#{@key}' to String!"
|
195
|
+
end
|
196
|
+
|
197
|
+
def inspect
|
198
|
+
nil.inspect
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
class << self
|
204
|
+
def forbidden! key
|
205
|
+
raise "direct modifications of SafeHash is forbidden, use :merge instead (you are trying to assign :#{key} value)!"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
protected
|
211
|
+
def p *a
|
212
|
+
::Object.send :p, *a
|
213
|
+
end
|
214
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'monitor'
|
2
2
|
|
3
|
-
|
3
|
+
Module.class_eval do
|
4
4
|
def synchronize_method *methods
|
5
5
|
methods.each do |method|
|
6
|
-
raise "
|
6
|
+
raise "can't synchronize system method #{method}" if method =~ /^__/
|
7
7
|
|
8
|
-
als = "sync_#{escape_method(method)}"
|
8
|
+
als = "sync_#{escape_method(method)}".to_sym
|
9
9
|
|
10
|
-
raise "
|
10
|
+
raise "can't synchronize the '#{method}' twice!" if instance_methods.include?(als)
|
11
11
|
|
12
12
|
alias_method als, method
|
13
13
|
script = "\
|
@@ -20,7 +20,7 @@ end"
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def synchronize_all_methods include_super = false
|
23
|
-
methods = self.instance_methods(include_super).collect{|m| m
|
23
|
+
methods = self.instance_methods(include_super).collect{|m| m}
|
24
24
|
synchronize_method *methods
|
25
25
|
end
|
26
26
|
end
|
File without changes
|
data/lib/yaml_fix.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'psych'
|
5
|
+
YAML::ENGINE.yamler = 'psych'
|
6
|
+
rescue Exception
|
7
|
+
warn "can't load 'psych', the new YAML engine (probably the 'libyaml' is not installed), usng 'sych' a deprecated one, \
|
8
|
+
there may be some problems with encoding."
|
9
|
+
end
|
data/readme.md
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
# Ruby extensions
|
2
|
-
**
|
2
|
+
**ruby_ext** is a collection of various utility classes and standard library extensions for the Ruby language.
|
3
3
|
|
4
4
|
## must - assertion tool, kind of RSpec assertions in runtime code
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
12
|
|
13
13
|
## inherit - combines include & extend in one
|
14
14
|
Do you remember this *def self.included(base) ... end* hack? You don't need it anymore.
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
30
|
## cache_method & synchronize_method
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def complex_calculation
|
33
|
+
2 * 2
|
34
|
+
end
|
35
|
+
cache_method :complex_calculation
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
def money_transfer amount
|
38
|
+
@from -= amount
|
39
|
+
@to += amount
|
40
|
+
end
|
41
|
+
synchronize_method :money_transfer
|
42
42
|
|
43
43
|
## OpenConstructor - adds mass assignment to any class
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
|
45
|
+
class TheClass
|
46
|
+
include OpenConstructor
|
47
|
+
attr_accessor :a, :b
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
o = TheClass.new.set a: 'a', b: 'b'
|
51
|
+
o.a => 'a'
|
52
|
+
o.to_hash => {a: 'a', b: 'b'}
|
53
53
|
|
54
54
|
## More
|
55
55
|
|
@@ -57,10 +57,14 @@ These are just a small part of all handy methods and extensions, for more detail
|
|
57
57
|
|
58
58
|
# Usage
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
$ sudo gem install ruby_ext
|
61
|
+
|
62
|
+
require 'ruby_ext'
|
63
63
|
|
64
|
-
Copyright (c)
|
64
|
+
Copyright (c) Alexey Petrushin [http://4ire.net](http://4ire.net), released under the MIT license.
|
65
|
+
|
66
|
+
# TODO
|
67
|
+
|
68
|
+
- config.development{} should raise 'invalid usage'
|
65
69
|
|
66
70
|
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|