caruby-core 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|