qualitysmith_extensions 0.0.34 → 0.0.49

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. data/lib/qualitysmith_extensions/array/shell_escape.rb +2 -2
  2. data/lib/qualitysmith_extensions/kernel/remove_const.rb +178 -0
  3. data/lib/qualitysmith_extensions/kernel/remove_module.rb +127 -0
  4. data/lib/qualitysmith_extensions/module/ancestry_of_instance_method.rb +43 -0
  5. data/lib/qualitysmith_extensions/module/attribute_accessors.rb +3 -0
  6. data/lib/qualitysmith_extensions/module/basename.rb +76 -0
  7. data/lib/qualitysmith_extensions/module/class_methods.rb +87 -0
  8. data/lib/qualitysmith_extensions/module/create.rb +315 -0
  9. data/lib/qualitysmith_extensions/module/dirname.rb +4 -0
  10. data/lib/qualitysmith_extensions/module/guard_method.rb +0 -1
  11. data/lib/qualitysmith_extensions/module/join.rb +66 -0
  12. data/lib/qualitysmith_extensions/module/module_methods.rb +4 -0
  13. data/lib/qualitysmith_extensions/module/namespace.rb +111 -0
  14. data/lib/qualitysmith_extensions/module/parents.rb +61 -0
  15. data/lib/qualitysmith_extensions/module/remove_const.rb +117 -0
  16. data/lib/qualitysmith_extensions/module/split.rb +55 -0
  17. data/lib/qualitysmith_extensions/object/ancestry_of_method.rb +257 -0
  18. data/lib/qualitysmith_extensions/object/methods.rb +7 -2
  19. data/lib/qualitysmith_extensions/string/constantize.rb +4 -0
  20. data/lib/qualitysmith_extensions/string/shell_escape.rb +1 -1
  21. data/lib/qualitysmith_extensions/symbol/constantize.rb +69 -0
  22. data/lib/qualitysmith_extensions/template.rb +1 -0
  23. data/lib/qualitysmith_extensions/test/assert_anything.rb +93 -0
  24. metadata +19 -3
  25. data/lib/qualitysmith_extensions/class/class_methods.rb +0 -5
@@ -2,11 +2,11 @@
2
2
  # Author:: Tyler Rick
3
3
  # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
4
  # License:: Ruby License
5
- # Submit to Facets?:: Yes. Symbol#to_proc -> Facets
5
+ # Submit to Facets?:: Yes.
6
6
  #++
7
7
 
8
8
  require 'rubygems'
9
- require 'extensions/symbol' unless Symbol.method_defined?(:to_proc)
9
+ require 'facets/core/symbol/to_proc' unless Symbol.method_defined?(:to_proc)
10
10
  require 'facets/core/kernel/require_local'
11
11
  require_local '../string/shell_escape.rb'
12
12
 
@@ -0,0 +1,178 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes!
6
+ # Developer notes::
7
+ #++
8
+
9
+ require 'rubygems'
10
+ require 'qualitysmith_extensions/object/ignore_access'
11
+ require 'qualitysmith_extensions/module/split'
12
+ require 'facets/core/module/by_name'
13
+ require 'facets/core/module/modspace'
14
+
15
+ class Module
16
+ alias_method :remove_const_before_was_added_to_Kernel, :remove_const
17
+ end
18
+ module Kernel
19
+ # This is similar to the built-in <tt>Module#remove_const</tt>, but it is accessible from all "levels" (because it is defined
20
+ # in +Kernel+) and can handle hierarchy.
21
+ #
22
+ # Makes it possible to write simply:
23
+ # remove_const(A::B::C.name)
24
+ # rather than having to think about which module the constant is actually defined in and calling +remove_const+ on that module.
25
+ #
26
+ # This is how you would otherwise have to do it:
27
+ # A::B.send(:remove_const, :C)
28
+ #
29
+ # +const_name+ must be an object that responds to +to_s+.
30
+ #
31
+ # +const_name+ must be a <i>fully qualified name</i>. For example, this will not work as expected:
32
+ #
33
+ # module Mod
34
+ # Foo = 'foo'
35
+ # remove_const(:Foo)
36
+ # end
37
+ #
38
+ # because it will try to remove ::Foo instead of Mod::Foo. Fortunately, however, this will work as expected:
39
+ #
40
+ # module Mod
41
+ # Foo = 'foo'
42
+ # remove_const(Foo.name)
43
+ # end
44
+ #
45
+ # This method is partially inspired by Facets' Kernel#constant method, which provided a more user-friendly alternative to const_get.
46
+ #
47
+ def remove_const(const_name)
48
+ #require 'pp'
49
+ #puts "remove_const(#{const_name})"
50
+ raise ArgumentError unless const_name.respond_to?(:to_s)
51
+ nesting = const_name.to_s.split(/::/).map(&:to_sym)
52
+ if nesting.size > 1
53
+ parent_module = constant(nesting[0..-2].join('::')) # For example, would be A::B for A::B::C
54
+ const_to_remove = nesting[-1] # For example, would be :C for A::B::C
55
+ parent_module.ignore_access.remove_const_before_was_added_to_Kernel(const_to_remove)
56
+ else
57
+ ignore_access.remove_const_before_was_added_to_Kernel(const_name)
58
+ end
59
+ end
60
+ end
61
+
62
+ #p Module.private_instance_methods.grep(/remove_const/) # Lists it
63
+ Module.send(:remove_method, :remove_const)
64
+ #p Module.instance_methods.grep(/remove_const/) # Does list it, because inherits *public* remove_const from Kernel
65
+ #p Module.private_instance_methods.grep(/remove_const/) # Does not list it, because it's no longer private
66
+ Module.send(:define_method, :remove_const, Kernel.method(:remove_const))
67
+ #p Module.private_instance_methods.grep(/remove_const/) # Lists it
68
+
69
+ # _____ _
70
+ # |_ _|__ ___| |_
71
+ # | |/ _ \/ __| __|
72
+ # | | __/\__ \ |_
73
+ # |_|\___||___/\__|
74
+ #
75
+ =begin test
76
+ require 'test/unit'
77
+
78
+ # Important regression test. This was failing at one point.
79
+ module A
80
+ B = nil
81
+ remove_const :B
82
+ end
83
+
84
+ # How it would be done *without* this extension:
85
+ module TestRemoveABC_TheOldWay
86
+ module A
87
+ module B
88
+ C = 'foo'
89
+ end
90
+ end
91
+
92
+ class TheTest < Test::Unit::TestCase
93
+ def test_1
94
+ assert_nothing_raised { A::B::C }
95
+ A::B.send(:remove_const, :C)
96
+ assert_raise(NameError) { A::B::C }
97
+ end
98
+ end
99
+ end
100
+
101
+ # How it would be done *with* this extension (all tests that follow):
102
+
103
+ module TestRemoveABC_CIsString
104
+ module A
105
+ module B
106
+ C = 'foo'
107
+ end
108
+ end
109
+
110
+ class TheTest < Test::Unit::TestCase
111
+ def test_1
112
+ assert_nothing_raised { A::B::C }
113
+ assert_raise(NoMethodError) { remove_const(A::B::C.name) } # Because C is a *string*, not a *module*
114
+ assert_nothing_raised { remove_const A::B.name + '::C' }
115
+ assert_raise(NameError) { A::B::C }
116
+ end
117
+ end
118
+ end
119
+
120
+ module TestRemoveAB_UsingName
121
+ module A
122
+ module B
123
+ end
124
+ end
125
+
126
+ class TheTest < Test::Unit::TestCase
127
+ def test_1
128
+ assert_nothing_raised { A::B }
129
+ remove_const(A::B.name)
130
+ assert_raise(NameError) { A::B }
131
+ end
132
+ end
133
+ end
134
+
135
+ module TestRemoveAB_Symbol
136
+ module A
137
+ module B
138
+ Foo = :Foo
139
+ end
140
+ end
141
+
142
+ remove_const(:'A::B::Foo') # This tests that Module#remove_const was overriden as well.
143
+ # If we hadn't also overriden Module#remove_const, then this would have caused this error:
144
+ # in `remove_const': `A::B::Foo' is not allowed as a constant name (NameError)
145
+
146
+ class TheTest < Test::Unit::TestCase
147
+ def test_1
148
+ assert_nothing_raised { A::B }
149
+
150
+ assert_equal 'TestRemoveAB_Symbol::A', A.name
151
+ assert_raise(NameError) { remove_const(:'A::B') } # This doesn't work because A, when evaluated in this context,
152
+ # is TestRemoveAB_Symbol::TheTest::A, which is *not* defined.
153
+
154
+ remove_const(:'TestRemoveAB_Symbol::A::B')
155
+ assert_raise(NameError) { A::B }
156
+ end
157
+ end
158
+ end
159
+
160
+ module TestRemoveAB_Symbol2
161
+ class TheTest < Test::Unit::TestCase
162
+ module A
163
+ module B
164
+ end
165
+ end
166
+ def test_1
167
+ assert_nothing_raised { A::B }
168
+
169
+ assert_equal 'TestRemoveAB_Symbol2::TheTest::A', A.name
170
+ remove_const(:'A::B') # Does work, because A is defined *within* TheTest this time.
171
+ assert_raise(NameError) { A::B }
172
+ end
173
+ end
174
+ end
175
+
176
+ =end
177
+
178
+
@@ -0,0 +1,127 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: No.
6
+ # Developer notes::
7
+ # * Deprecated by qualitysmith_extensions/module/remove.rb
8
+ #++
9
+
10
+ require 'rubygems'
11
+ require 'qualitysmith_extensions/object/ignore_access'
12
+ require 'qualitysmith_extensions/module/split'
13
+ require 'facets/core/module/by_name'
14
+ require 'facets/core/module/modspace'
15
+
16
+ module Kernel
17
+ # This is similar to +remove_const+, but it _only_ works for modules/classes.
18
+ #
19
+ # This is similar to the built-in <tt>Module#remove_module</tt>, but it is accessible from all "levels" (because it is defined
20
+ # in +Kernel+) and can handle hierarchy.
21
+ #
22
+ # Makes it possible to write simply:
23
+ # remove_module(A::B::C)
24
+ # rather than having to think about which module the constant is actually defined in and calling +remove_const+ on that module.
25
+ # This is how you would have to otherwise do it:
26
+ # A::B.send(:remove_const, :C)
27
+ #
28
+ # You can pass in either a constant or a symbol. Passing in a constant is preferred
29
+ #
30
+ # This method is partially inspired by Facets' Kernel#constant method, which provided a more user-friendly alternative to const_get.
31
+ #
32
+ def remove_module(const)
33
+ const = Module.by_name(const.to_s) if const.is_a?(Symbol)
34
+ if const.split.size > 1
35
+ parent_module = const.modspace # For example, would be A::B for A::B::C
36
+ const_to_remove = const.split.last # For example, would be :C for A::B::C
37
+ parent_module.ignore_access.remove_const(const_to_remove)
38
+ else
39
+ Object.ignore_access.remove_const(const.name)
40
+ end
41
+ end
42
+ end
43
+
44
+ # _____ _
45
+ # |_ _|__ ___| |_
46
+ # | |/ _ \/ __| __|
47
+ # | | __/\__ \ |_
48
+ # |_|\___||___/\__|
49
+ #
50
+ =begin test
51
+ require 'test/unit'
52
+ require 'qualitysmith_extensions/kernel/remove_const' # Test for compatibility. Just in case the remove_const_before_was_added_to_Kernel alias might have thrown something off.
53
+
54
+ # How it would be done *without* this extension:
55
+ module TestRemoveABC_TheOldWay
56
+ module A
57
+ module B
58
+ class C
59
+ end
60
+ end
61
+ end
62
+
63
+ class TheTest < Test::Unit::TestCase
64
+ def test_1
65
+ assert_nothing_raised { A::B::C }
66
+ A::B.send(:remove_const, :C)
67
+ assert_raise(NameError) { A::B::C }
68
+ end
69
+ end
70
+ end
71
+
72
+ # How it would be done *with* this extension:
73
+ module TestRemoveABC
74
+ module A
75
+ module B
76
+ class C
77
+ end
78
+ end
79
+ end
80
+
81
+ class TheTest < Test::Unit::TestCase
82
+ def test_1
83
+ assert_nothing_raised { A::B::C }
84
+ remove_module(A::B::C)
85
+ assert_raise(NameError) { A::B::C }
86
+ end
87
+ end
88
+ end
89
+
90
+ module TestRemoveAB
91
+ module A
92
+ module B
93
+ module C
94
+ end
95
+ end
96
+ end
97
+
98
+ class TheTest < Test::Unit::TestCase
99
+ def test_1
100
+ assert_nothing_raised { A::B }
101
+ remove_module(A::B)
102
+ assert_raise(NameError) { A::B }
103
+ end
104
+ end
105
+ end
106
+
107
+ module TestRemoveAB_Symbol
108
+ module A
109
+ module B
110
+ module C
111
+ end
112
+ end
113
+ end
114
+
115
+ class TheTest < Test::Unit::TestCase
116
+ def test_1
117
+ assert_nothing_raised { A::B }
118
+ assert_raise(NameError) { remove_module(:'A::B') } # This is why passing in the module itself is preferred.
119
+ remove_module(:'TestRemoveAB_Symbol::A::B')
120
+ assert_raise(NameError) { A::B }
121
+ end
122
+ end
123
+ end
124
+
125
+ =end
126
+
127
+
@@ -0,0 +1,43 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes.
6
+ # Developer notes::
7
+ # * May not have taken every single case into consideration. Needs a bit more testing.
8
+ # * public/private/protected?
9
+ # * Tests for this method can be found in ../object/ancestry_of_method.rb . It made more sense to test those two methods together;
10
+ # yet it's still to _use_ module/ancestry_of_instance_method.rb without using ../object/ancestry_of_method.rb.
11
+ #++
12
+
13
+ class Module
14
+
15
+ # Returns the module/class which defined the given instance method. If more than one module/class defined the method, returns the _closest_
16
+ # ancestor to have defined it (would be +self+ if it is defined in +self+).
17
+ #
18
+ # This looks at the results of <tt>instance_methods</tt>, which means that if you call this on a module/class, it will _only_ look
19
+ # at _instance_ methods. Thus, (unlike +ancestry_of_method+) it _only_ makes sense to call this method on modules/classes,
20
+ # not _instances_ of those modules/classes.
21
+ #
22
+ # Example:
23
+ # class Base
24
+ # def it; end
25
+ # end
26
+ # class SubWithIt < Base
27
+ # def it; end
28
+ # end
29
+ # class SubWithoutIt < Base
30
+ # end
31
+ # SubWithIt.ancestors # => [SubWithIt, Base, Object, Kernel]
32
+ # SubWithIt.ancestry_of_instance_method(:it) # => SubWithIt # (Stops with self)
33
+ # SubWithoutIt.ancestry_of_instance_method(:it) # => Base # (Goes one step up the ancestry tree)
34
+ #
35
+ # Returns nil if it cannot be found in self or in any ancestor.
36
+ def ancestry_of_instance_method(method_name)
37
+ method_name = method_name.to_s
38
+ self.ancestors.find do |ancestor|
39
+ ancestor.instance_methods(false).include? method_name
40
+ end
41
+ end
42
+
43
+ end
@@ -20,6 +20,7 @@ class Module # :nodoc:
20
20
  EOS
21
21
  end
22
22
  end
23
+ alias_method :cattr_reader, :mattr_reader
23
24
 
24
25
  def mattr_writer(*syms)
25
26
  syms.each do |sym|
@@ -38,9 +39,11 @@ class Module # :nodoc:
38
39
  EOS
39
40
  end
40
41
  end
42
+ alias_method :cattr_writer, :mattr_writer
41
43
 
42
44
  def mattr_accessor(*syms)
43
45
  mattr_reader(*syms)
44
46
  mattr_writer(*syms)
45
47
  end
48
+ alias_method :cattr_accessor, :mattr_accessor
46
49
  end
@@ -0,0 +1,76 @@
1
+ #--
2
+ # Author:: Tyler Rick
3
+ # Copyright:: Copyright (c) 2007 QualitySmith, Inc.
4
+ # License:: Ruby License
5
+ # Submit to Facets?:: Yes.
6
+ # Developer notes::
7
+ # Changes::
8
+ #++
9
+
10
+
11
+ require 'rubygems'
12
+ require 'facets/core/module/basename'
13
+ require 'facets/core/string/basename'
14
+ require 'qualitysmith_extensions/module/namespace'
15
+
16
+ class Module
17
+ # Gets the basename of a "module path" (the name of the module without any of the namespace modules that it is contained in),
18
+ # in the same sense that <tt>File.basename</tt> returns the basename of a _filesystem_ path.
19
+ #
20
+ # This is identical to Facets' String#basename ('facets/core/string/basename') except that:
21
+ # * it is a class method instead of an instance method of String,
22
+ # * it accepts modules, strings, and symbols.
23
+ #
24
+ # See also <tt>Module.dirname</tt>/<tt>Module.namespace_name_of</tt>.
25
+ #
26
+ # These can be used together, such that the following is always true:
27
+ # OuterModule::MiddleModule::InnerModule == Module.join(Module.dirname(some_module), Module.basename(some_module)).constantize
28
+ #
29
+ def self.basename(module_or_name)
30
+ case module_or_name
31
+ when Module
32
+ module_or_name.basename
33
+ when Symbol
34
+ module_or_name.to_s.basename
35
+ when String
36
+ module_or_name.basename
37
+ else
38
+ raise ArgumentError
39
+ end
40
+ end
41
+ end
42
+
43
+
44
+
45
+
46
+ # _____ _
47
+ # |_ _|__ ___| |_
48
+ # | |/ _ \/ __| __|
49
+ # | | __/\__ \ |_
50
+ # |_|\___||___/\__|
51
+ #
52
+ =begin test
53
+ require 'test/unit'
54
+
55
+ module OuterModule; end
56
+ module OuterModule::MiddleModule; end
57
+ module OuterModule::MiddleModule::InnerModule; end
58
+
59
+ class BasenameTest < Test::Unit::TestCase
60
+ def test_simple
61
+ assert_equal 'OuterModule', Module.basename(OuterModule)
62
+ assert_equal 'OuterModule', Module.basename(:OuterModule)
63
+ assert_equal 'OuterModule', Module.basename('OuterModule')
64
+ end
65
+ def test_nesting
66
+ assert_equal 'InnerModule',
67
+ Module.basename(OuterModule::MiddleModule::InnerModule)
68
+ assert_equal 'InnerModule',
69
+ Module.basename(:'OuterModule::MiddleModule::InnerModule')
70
+ assert_equal 'InnerModule',
71
+ Module.basename('OuterModule::MiddleModule::InnerModule')
72
+ end
73
+ end
74
+ =end
75
+
76
+