caruby-core 1.4.1
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.
- data/History.txt +4 -0
- data/LEGAL +5 -0
- data/LICENSE +22 -0
- data/README.md +51 -0
- data/doc/website/css/site.css +1 -5
- data/doc/website/images/avatar.png +0 -0
- data/doc/website/images/favicon.ico +0 -0
- data/doc/website/images/logo.png +0 -0
- data/doc/website/index.html +82 -0
- data/doc/website/install.html +87 -0
- data/doc/website/quick_start.html +87 -0
- data/doc/website/tissue.html +85 -0
- data/doc/website/uom.html +10 -0
- data/lib/caruby.rb +3 -0
- data/lib/caruby/active_support/README.txt +2 -0
- data/lib/caruby/active_support/core_ext/string.rb +7 -0
- data/lib/caruby/active_support/core_ext/string/inflections.rb +167 -0
- data/lib/caruby/active_support/inflections.rb +55 -0
- data/lib/caruby/active_support/inflector.rb +398 -0
- data/lib/caruby/cli/application.rb +36 -0
- data/lib/caruby/cli/command.rb +169 -0
- data/lib/caruby/csv/csv_mapper.rb +157 -0
- data/lib/caruby/csv/csvio.rb +185 -0
- data/lib/caruby/database.rb +252 -0
- data/lib/caruby/database/fetched_matcher.rb +66 -0
- data/lib/caruby/database/persistable.rb +432 -0
- data/lib/caruby/database/persistence_service.rb +162 -0
- data/lib/caruby/database/reader.rb +599 -0
- data/lib/caruby/database/saved_merger.rb +131 -0
- data/lib/caruby/database/search_template_builder.rb +59 -0
- data/lib/caruby/database/sql_executor.rb +75 -0
- data/lib/caruby/database/store_template_builder.rb +200 -0
- data/lib/caruby/database/writer.rb +469 -0
- data/lib/caruby/domain/annotatable.rb +25 -0
- data/lib/caruby/domain/annotation.rb +23 -0
- data/lib/caruby/domain/attribute_metadata.rb +447 -0
- data/lib/caruby/domain/java_attribute_metadata.rb +160 -0
- data/lib/caruby/domain/merge.rb +91 -0
- data/lib/caruby/domain/properties.rb +95 -0
- data/lib/caruby/domain/reference_visitor.rb +289 -0
- data/lib/caruby/domain/resource_attributes.rb +528 -0
- data/lib/caruby/domain/resource_dependency.rb +205 -0
- data/lib/caruby/domain/resource_introspection.rb +159 -0
- data/lib/caruby/domain/resource_metadata.rb +117 -0
- data/lib/caruby/domain/resource_module.rb +285 -0
- data/lib/caruby/domain/uniquify.rb +38 -0
- data/lib/caruby/import/annotatable_class.rb +28 -0
- data/lib/caruby/import/annotation_class.rb +27 -0
- data/lib/caruby/import/annotation_module.rb +67 -0
- data/lib/caruby/import/java.rb +338 -0
- data/lib/caruby/migration/migratable.rb +167 -0
- data/lib/caruby/migration/migrator.rb +533 -0
- data/lib/caruby/migration/resource.rb +8 -0
- data/lib/caruby/migration/resource_module.rb +11 -0
- data/lib/caruby/migration/uniquify.rb +20 -0
- data/lib/caruby/resource.rb +969 -0
- data/lib/caruby/util/attribute_path.rb +46 -0
- data/lib/caruby/util/cache.rb +53 -0
- data/lib/caruby/util/class.rb +99 -0
- data/lib/caruby/util/collection.rb +1053 -0
- data/lib/caruby/util/controlled_value.rb +35 -0
- data/lib/caruby/util/coordinate.rb +75 -0
- data/lib/caruby/util/domain_extent.rb +49 -0
- data/lib/caruby/util/file_separator.rb +65 -0
- data/lib/caruby/util/inflector.rb +20 -0
- data/lib/caruby/util/log.rb +95 -0
- data/lib/caruby/util/math.rb +12 -0
- data/lib/caruby/util/merge.rb +59 -0
- data/lib/caruby/util/module.rb +34 -0
- data/lib/caruby/util/options.rb +92 -0
- data/lib/caruby/util/partial_order.rb +36 -0
- data/lib/caruby/util/person.rb +119 -0
- data/lib/caruby/util/pretty_print.rb +184 -0
- data/lib/caruby/util/properties.rb +112 -0
- data/lib/caruby/util/stopwatch.rb +66 -0
- data/lib/caruby/util/topological_sync_enumerator.rb +53 -0
- data/lib/caruby/util/transitive_closure.rb +45 -0
- data/lib/caruby/util/tree.rb +48 -0
- data/lib/caruby/util/trie.rb +37 -0
- data/lib/caruby/util/uniquifier.rb +30 -0
- data/lib/caruby/util/validation.rb +48 -0
- data/lib/caruby/util/version.rb +56 -0
- data/lib/caruby/util/visitor.rb +351 -0
- data/lib/caruby/util/weak_hash.rb +36 -0
- data/lib/caruby/version.rb +3 -0
- metadata +186 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module CaRuby
|
4
|
+
class ControlledValue
|
5
|
+
attr_accessor :value, :parent
|
6
|
+
|
7
|
+
attr_reader :children
|
8
|
+
|
9
|
+
# Creates a new ControlledValue with the given String value and ControlledValue parent.
|
10
|
+
# If parent is not nil, then the new CV is added to the parent's children.
|
11
|
+
def initialize(value=nil, parent=nil)
|
12
|
+
@value = value
|
13
|
+
self.parent = parent
|
14
|
+
@children = Set.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def descendants
|
18
|
+
children + children.map { |child| child.descendants.to_a }.flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
value
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Sets this CV's parent and adds this CV to the parent's children if necessary.
|
28
|
+
def parent=(parent)
|
29
|
+
@parent.children.delete(self) if @parent
|
30
|
+
@parent = parent
|
31
|
+
parent.children << self if parent
|
32
|
+
parent
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'generator'
|
2
|
+
|
3
|
+
# A Coordinate is a convenience Array wrapper class with aliased #x, #y and {#z} dimensions.
|
4
|
+
class Coordinate < Array
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
# @param [{Integer}] scalars the dimension coordinate values
|
8
|
+
# @return a new Coordinate at the given scalars
|
9
|
+
def initialize(*scalars)
|
10
|
+
super(scalars)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Integer] the first dimension
|
14
|
+
def x
|
15
|
+
self[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [Integer] the first dimension value
|
19
|
+
def x=(value)
|
20
|
+
self[0] = value
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Integer, nil] the second dimension
|
24
|
+
def y
|
25
|
+
self[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Integer] the second dimension value
|
29
|
+
def y=(value)
|
30
|
+
self[1] = value
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Integer, nil] the third dimension
|
34
|
+
def z
|
35
|
+
self[2]
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [Integer] the third dimension value
|
39
|
+
def z=(value)
|
40
|
+
self[2] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Boolean] whether other is a Coordinate and has the same content as this Coordinate
|
44
|
+
def ==(other)
|
45
|
+
super rescue false
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the comparison of the highest dimension which differs from the other
|
49
|
+
# coordinate, or zero if all dimensions are the same. This comparator sorts
|
50
|
+
# coordinates in z-y-x order.
|
51
|
+
# @example
|
52
|
+
# Coordinate.new(2, 1) < Coordinate.new(1, 2) #=> true
|
53
|
+
# @return [Integer] the high-to-low dimension comparison
|
54
|
+
# @raise [ArgumentError] if this Coordinate dimension size Coordinate differs from that
|
55
|
+
# of the other Dimension or any of the dimension values are nil
|
56
|
+
# @raise [TypeError] if other is not a Coordinate
|
57
|
+
def <=>(other)
|
58
|
+
return true if equal?(other)
|
59
|
+
raise TypeError.new("Can't compare #{self} with #{other} since it is not a Coordinate") unless Coordinate === other
|
60
|
+
raise ArgumentError.new("Can't compare #{self} with #{other} since it has a different dimension count") unless size == other.size
|
61
|
+
SyncEnumerator.new(self.reverse, other.reverse).each_with_index do |pair, index|
|
62
|
+
dim = pair.first
|
63
|
+
odim = pair.last
|
64
|
+
raise ArgumentError.new("Can't compare #{self} with missing dimension #{index} to #{other}") unless dim
|
65
|
+
raise ArgumentError.new("Can't compare #{self} to #{other} with missing dimension #{index}") unless odim
|
66
|
+
cmp = dim <=> odim
|
67
|
+
return cmp unless cmp.zero?
|
68
|
+
end
|
69
|
+
0
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
inspect
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'caruby/util/collection'
|
2
|
+
require 'caruby/util/validation'
|
3
|
+
|
4
|
+
# A DomainExtent contains class-specific key => object associations.
|
5
|
+
# The objects are created on demand and accessed by the get method.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# DomainExtent.new { |klass, key| key.to_s + klass.name }.get(String, 'a') #=> aString
|
9
|
+
class DomainExtent < LazyHash
|
10
|
+
include Validation
|
11
|
+
|
12
|
+
# Creates a new DomainExtent. The block passed to the constructor
|
13
|
+
# is a factory to create an object on demand, with arguments
|
14
|
+
# the target class and the target key. The default block is empty.
|
15
|
+
def initialize
|
16
|
+
return initialize {} unless block_given?
|
17
|
+
super { |klass| LazyHash.new { |key| yield klass, key } }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Sets the factory used to create an instance of the specified class.
|
21
|
+
# The factory is called to create a new instance when a get operation
|
22
|
+
# does not yet have a key => instance association.
|
23
|
+
#
|
24
|
+
# The factory accepts a single argument, the instance key, e.g.
|
25
|
+
# set_factory(MyClass) { |key| MyClass.new(key) }
|
26
|
+
def set_factory(klass, &factory)
|
27
|
+
validate_type(klass => Class)
|
28
|
+
# the current instances, if any
|
29
|
+
instances = fetch(klass) if has_key?(klass)
|
30
|
+
# make the key => instance class extent map
|
31
|
+
# the instance creation factory is
|
32
|
+
class_extent = LazyHash.new { |key| yield key }
|
33
|
+
# copy existing instances if necessary
|
34
|
+
class_extent.merge!(instances) if instances
|
35
|
+
# add the class => class extent association
|
36
|
+
self[klass] = class_extent
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the domain instance of the given class for the given key.
|
40
|
+
# If there is nois no entry for key and the factory is set for the class,
|
41
|
+
# then a new object is created on demand.
|
42
|
+
def get(klass, key)
|
43
|
+
raise RuntimeError.new("Invalid target class: #{klass}") unless klass.is_a?(Class)
|
44
|
+
raise RuntimeError.new("Missing target key value") if key.nil?
|
45
|
+
# the class extent hash is created on demand if necessary.
|
46
|
+
# the instance is created on demand if there is a factory for the class.
|
47
|
+
self[klass][key]
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'caruby/util/class'
|
2
|
+
|
3
|
+
class File
|
4
|
+
[:gets, :readline, :readlines].each do |attr|
|
5
|
+
# Overrides the standard method to infer a line separator from the input
|
6
|
+
# if the separator argument is the default.
|
7
|
+
redefine_method(attr) do |original|
|
8
|
+
lambda do |*params|
|
9
|
+
sep = params.first || default_line_separator
|
10
|
+
send(original, sep)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Overrides the standard {#each} method to infer a line separator from the input
|
15
|
+
# if the separator argument is not given.
|
16
|
+
def each(separator=nil)
|
17
|
+
while (line = gets(separator)) do
|
18
|
+
yield line
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Returns the default line separator. The logic is borrowed from the FasterCVS gem.
|
26
|
+
def default_line_separator
|
27
|
+
@def_line_sep ||= infer_line_separator
|
28
|
+
end
|
29
|
+
|
30
|
+
def infer_line_separator
|
31
|
+
type_line_separator or content_line_separator or $/
|
32
|
+
end
|
33
|
+
|
34
|
+
def type_line_separator
|
35
|
+
if [ARGF, STDIN, STDOUT, STDERR].include?(self) or
|
36
|
+
(defined?(Zlib) and self.class == Zlib::GzipWriter) then
|
37
|
+
return $/
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def content_line_separator
|
42
|
+
begin
|
43
|
+
saved_pos = pos # remember where we were
|
44
|
+
# read a chunk until a separator is discovered
|
45
|
+
sep = discover_line_separator
|
46
|
+
# tricky seek() clone to work around GzipReader's lack of seek()
|
47
|
+
rewind
|
48
|
+
# reset back to the remembered position
|
49
|
+
chunks, residual = saved_pos.divmod(1024)
|
50
|
+
chunks.times { read(1024) }
|
51
|
+
read(residual)
|
52
|
+
rescue IOError # stream not opened for reading
|
53
|
+
end
|
54
|
+
sep
|
55
|
+
end
|
56
|
+
|
57
|
+
def discover_line_separator
|
58
|
+
# read a chunk until a separator is discovered
|
59
|
+
while (sample = read(1024)) do
|
60
|
+
sample += read(1) if sample[-1, 1] == "\r" and not eof?
|
61
|
+
# try to find a standard separator
|
62
|
+
return $& if sample =~ /\r\n?|\n/
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'caruby/active_support/inflector'
|
2
|
+
|
3
|
+
class String
|
4
|
+
# @param [Numeric] quantity the amount qualifier
|
5
|
+
# @return this String qualified by a plural if the quantity is not 1
|
6
|
+
# @example
|
7
|
+
# "rose".quantify(3) #=> "roses"
|
8
|
+
# "rose".quantify(1 #=> "rose"
|
9
|
+
def quantify(quantity)
|
10
|
+
raise ArgumentError.new("Missing quantity argument") if quantity.nil?
|
11
|
+
"#{quantity} #{quantity == 1 ? self : pluralize}"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return this String with the first letter capitalized and other letters preserved.
|
15
|
+
# @example
|
16
|
+
# "rosesAreRed".capitalize_first #=> "RosesAreRed"
|
17
|
+
def capitalize_first
|
18
|
+
sub(/(?:^)(.)/) { $1.upcase }
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'singleton'
|
3
|
+
require 'ftools'
|
4
|
+
require 'caruby/util/collection'
|
5
|
+
|
6
|
+
# @return [CaRuby::Logger] the global logger
|
7
|
+
def logger
|
8
|
+
CaRuby::Log::instance.logger
|
9
|
+
end
|
10
|
+
|
11
|
+
module CaRuby
|
12
|
+
# Extends the standard Logger to format multi-line messages on separate lines.
|
13
|
+
class MultilineLogger < Logger
|
14
|
+
# @see Logger#initialize
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Writes msg to the log device. Each line in msg is formatted separately.
|
22
|
+
#
|
23
|
+
# @param (see Logger#format_message)
|
24
|
+
# @return (see Logger#format_message)
|
25
|
+
def format_message(severity, datetime, progname, msg)
|
26
|
+
if String === msg then
|
27
|
+
msg.inject('') { |s, line| s << super(severity, datetime, progname, line.chomp) }
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Wraps a standard global Logger.
|
35
|
+
class Log
|
36
|
+
include Singleton
|
37
|
+
|
38
|
+
# Opens the log.
|
39
|
+
#
|
40
|
+
# @param [String, IO, nil] file_or_dev the log file or device (default STDOUT)
|
41
|
+
# @param [Hash, nil] the Logger::LogDevice options
|
42
|
+
# @return [Logger] the logger
|
43
|
+
def open(file_or_dev=nil, options=nil)
|
44
|
+
dev = file_or_dev || default_log_file
|
45
|
+
return @logger if same_file?(dev, @dev)
|
46
|
+
# close the previous log file, if necessary
|
47
|
+
@logger.close if @logger
|
48
|
+
if String === dev then File.makedirs(File.dirname(dev)) end
|
49
|
+
# default is 4-file rotation @ 16MB each
|
50
|
+
shift_age = Options.get(:shift_age, options, 4)
|
51
|
+
shift_size = Options.get(:shift_size, options, 16 * 1048576)
|
52
|
+
@logger = MultilineLogger.new(dev, shift_age, shift_size)
|
53
|
+
@logger.level = Options.get(:debug, options) ? Logger::DEBUG : Logger::INFO
|
54
|
+
@logger.info('============================================')
|
55
|
+
@logger.info('Logging started.')
|
56
|
+
@dev = dev
|
57
|
+
@logger
|
58
|
+
end
|
59
|
+
|
60
|
+
def close
|
61
|
+
@logger.close
|
62
|
+
@logger = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the logger.
|
66
|
+
def logger
|
67
|
+
@logger ||= open
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String, nil] the log file, or nil if the log was opened on an IO rather
|
71
|
+
# than a String
|
72
|
+
def file
|
73
|
+
@dev if String === @dev
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def same_file?(f1, f2)
|
79
|
+
f1 == f2 or (String === f2 and String === f1 and File.expand_path(f1) == File.expand_path(f2))
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_log_file
|
83
|
+
log_ndx = ARGV.index("--log") || ARGV.index("-l")
|
84
|
+
if log_ndx then
|
85
|
+
ARGV[log_ndx + 1]
|
86
|
+
elsif ENV.has_key?("CA_LOG") then
|
87
|
+
ENV["CA_LOG"]
|
88
|
+
elsif defined?(DEF_LOG_FILE)
|
89
|
+
DEF_LOG_FILE
|
90
|
+
else
|
91
|
+
'log/caruby.log'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Extends the Numeric class with max and min methods.
|
2
|
+
class Numeric
|
3
|
+
# Returns the minimum of this Numeric and the other Numerics.
|
4
|
+
def min(*others)
|
5
|
+
others.inject(self) { |min, other| other < min ? other : min }
|
6
|
+
end
|
7
|
+
|
8
|
+
# Returns the minimum of this Numeric and the other Numerics.
|
9
|
+
def max(*others)
|
10
|
+
others.inject(self) { |max, other| other > max ? other : max }
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'caruby/util/options'
|
2
|
+
require 'caruby/util/collection'
|
3
|
+
|
4
|
+
class Hash
|
5
|
+
# Returns a new hash which merges the other hash with this hash.
|
6
|
+
#
|
7
|
+
# Supported options include the following:
|
8
|
+
# * :deep - merge values which match on the key.
|
9
|
+
# If the :deep option is set, and a key matches both this hash and the other hash
|
10
|
+
# on hash values, then the other hash's value is recursively merged into this Hash's
|
11
|
+
# value using the non-destructive {#merge} method with the deep option set.
|
12
|
+
# If a block is given to this method, then the block is passed to the value merge.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# {:a => [1], :b => [2]}.merge({:b => [3]}, :deep) #=> {:a => [1], :b => [2, 3]}
|
16
|
+
# {:a => {:b => [1]}}.merge({:a => {:b => [2]}, :c => 3}, :deep) #=> {:a => {:b => [1, 2]}, :c => 3}
|
17
|
+
def merge(other, options=nil, &block)
|
18
|
+
dup.merge!(other, options, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
alias :base__merge! :merge!
|
22
|
+
private :base__merge!
|
23
|
+
|
24
|
+
# Merges the other hash into this hash and returns this modified hash.
|
25
|
+
#
|
26
|
+
# @see #merge the options and block description
|
27
|
+
def merge!(other, options=nil, &block)
|
28
|
+
# use the standard Hash merge unless the :deep option is set
|
29
|
+
return base__merge!(other, &block) unless Options.get(:deep, options)
|
30
|
+
# merge the other entries:
|
31
|
+
# if the hash value is a hash, then call merge on that hash value.
|
32
|
+
# otherwise, if the hash value understands merge, then call that method.
|
33
|
+
# otherwise, if there is a block, then call the block.
|
34
|
+
# otherwise, set the the hash value to the other value.
|
35
|
+
base__merge!(other) do |key, oldval, newval|
|
36
|
+
if Hash === oldval then
|
37
|
+
oldval.merge(newval, options, &block)
|
38
|
+
elsif oldval.respond_to?(:merge)
|
39
|
+
oldval.merge(newval, &block)
|
40
|
+
elsif block_given? then
|
41
|
+
yield(key, oldval, newval)
|
42
|
+
else
|
43
|
+
newval
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Array
|
50
|
+
# Adds the elements in the other Enumerable which are not already included in this Array.
|
51
|
+
# Returns this modified Array.
|
52
|
+
def merge(other)
|
53
|
+
# incompatible merge argument is allowed but ignored
|
54
|
+
self unless Enumerable === other
|
55
|
+
# concatenate the members of other not in self
|
56
|
+
unique = other.to_a - self
|
57
|
+
concat(unique)
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Module
|
2
|
+
# Returns the class or module with name in the parent module.
|
3
|
+
# If parent is nil, then name is looked up in the global context.
|
4
|
+
# Otherwise, this method returns {#module_with_name}.
|
5
|
+
def self.module_with_name(parent, name)
|
6
|
+
return parent.module_with_name(name) if parent
|
7
|
+
begin
|
8
|
+
constant = eval(name)
|
9
|
+
rescue Exception
|
10
|
+
return
|
11
|
+
end
|
12
|
+
constant if constant.is_a?(Module)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the class or module with name in this module.
|
16
|
+
# name can qualified by parent modules, e.g. +MyApp::Person+.
|
17
|
+
# If name cannot be resolved as a Module, then this method returns nil.
|
18
|
+
def module_with_name(name)
|
19
|
+
begin
|
20
|
+
constant = name.split('::').inject(parent) { |parent, name| parent.const_get(name) }
|
21
|
+
rescue Exception
|
22
|
+
return
|
23
|
+
end
|
24
|
+
constant if constant.is_a?(Module)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the class with name in this module.
|
28
|
+
# name can qualified by parent modules, e.g. +MyApp::Person+.
|
29
|
+
# If name cannot be resolved as a Class, then this method returns nil.
|
30
|
+
def class_with_name
|
31
|
+
mod = module_with_name
|
32
|
+
mod if mod.is_a?(Class)
|
33
|
+
end
|
34
|
+
end
|