caruby-core 1.4.2 → 1.4.3
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 +10 -0
- data/lib/caruby/cli/command.rb +10 -8
- data/lib/caruby/database/fetched_matcher.rb +28 -39
- data/lib/caruby/database/lazy_loader.rb +101 -0
- data/lib/caruby/database/persistable.rb +190 -167
- data/lib/caruby/database/persistence_service.rb +21 -7
- data/lib/caruby/database/persistifier.rb +185 -0
- data/lib/caruby/database/reader.rb +106 -176
- data/lib/caruby/database/saved_matcher.rb +56 -0
- data/lib/caruby/database/search_template_builder.rb +1 -1
- data/lib/caruby/database/sql_executor.rb +8 -7
- data/lib/caruby/database/store_template_builder.rb +134 -61
- data/lib/caruby/database/writer.rb +252 -52
- data/lib/caruby/database.rb +88 -67
- data/lib/caruby/domain/attribute_initializer.rb +16 -0
- data/lib/caruby/domain/attribute_metadata.rb +161 -72
- data/lib/caruby/domain/id_alias.rb +22 -0
- data/lib/caruby/domain/inversible.rb +91 -0
- data/lib/caruby/domain/merge.rb +116 -35
- data/lib/caruby/domain/properties.rb +1 -1
- data/lib/caruby/domain/reference_visitor.rb +207 -71
- data/lib/caruby/domain/resource_attributes.rb +93 -80
- data/lib/caruby/domain/resource_dependency.rb +22 -97
- data/lib/caruby/domain/resource_introspection.rb +21 -28
- data/lib/caruby/domain/resource_inverse.rb +134 -0
- data/lib/caruby/domain/resource_metadata.rb +41 -19
- data/lib/caruby/domain/resource_module.rb +42 -33
- data/lib/caruby/import/java.rb +8 -9
- data/lib/caruby/migration/migrator.rb +20 -7
- data/lib/caruby/migration/resource_module.rb +0 -2
- data/lib/caruby/resource.rb +132 -351
- data/lib/caruby/util/cache.rb +4 -1
- data/lib/caruby/util/class.rb +48 -1
- data/lib/caruby/util/collection.rb +54 -18
- data/lib/caruby/util/inflector.rb +7 -0
- data/lib/caruby/util/options.rb +35 -31
- data/lib/caruby/util/partial_order.rb +1 -1
- data/lib/caruby/util/properties.rb +2 -2
- data/lib/caruby/util/stopwatch.rb +16 -8
- data/lib/caruby/util/transitive_closure.rb +1 -1
- data/lib/caruby/util/visitor.rb +342 -328
- data/lib/caruby/version.rb +1 -1
- data/lib/caruby/yard/resource_metadata_handler.rb +8 -0
- data/lib/caruby.rb +2 -0
- metadata +10 -9
- data/lib/caruby/database/saved_merger.rb +0 -131
- data/lib/caruby/domain/annotatable.rb +0 -25
- data/lib/caruby/domain/annotation.rb +0 -23
- data/lib/caruby/import/annotatable_class.rb +0 -28
- data/lib/caruby/import/annotation_class.rb +0 -27
- data/lib/caruby/import/annotation_module.rb +0 -67
- data/lib/caruby/migration/resource.rb +0 -8
data/lib/caruby/version.rb
CHANGED
data/lib/caruby.rb
CHANGED
metadata
CHANGED
@@ -6,11 +6,11 @@ executables: []
|
|
6
6
|
|
7
7
|
version: !ruby/object:Gem::Version
|
8
8
|
prerelease: false
|
9
|
-
version: 1.4.
|
9
|
+
version: 1.4.3
|
10
10
|
segments:
|
11
11
|
- 1
|
12
12
|
- 4
|
13
|
-
-
|
13
|
+
- 3
|
14
14
|
post_install_message:
|
15
15
|
date: 2010-11-30 08:00:00 +00:00
|
16
16
|
files:
|
@@ -28,17 +28,20 @@ files:
|
|
28
28
|
- lib/caruby/csv/csv_mapper.rb
|
29
29
|
- lib/caruby/csv/csvio.rb
|
30
30
|
- lib/caruby/database/fetched_matcher.rb
|
31
|
+
- lib/caruby/database/lazy_loader.rb
|
31
32
|
- lib/caruby/database/persistable.rb
|
32
33
|
- lib/caruby/database/persistence_service.rb
|
34
|
+
- lib/caruby/database/persistifier.rb
|
33
35
|
- lib/caruby/database/reader.rb
|
34
|
-
- lib/caruby/database/
|
36
|
+
- lib/caruby/database/saved_matcher.rb
|
35
37
|
- lib/caruby/database/search_template_builder.rb
|
36
38
|
- lib/caruby/database/sql_executor.rb
|
37
39
|
- lib/caruby/database/store_template_builder.rb
|
38
40
|
- lib/caruby/database/writer.rb
|
39
|
-
- lib/caruby/domain/
|
40
|
-
- lib/caruby/domain/annotation.rb
|
41
|
+
- lib/caruby/domain/attribute_initializer.rb
|
41
42
|
- lib/caruby/domain/attribute_metadata.rb
|
43
|
+
- lib/caruby/domain/id_alias.rb
|
44
|
+
- lib/caruby/domain/inversible.rb
|
42
45
|
- lib/caruby/domain/java_attribute_metadata.rb
|
43
46
|
- lib/caruby/domain/merge.rb
|
44
47
|
- lib/caruby/domain/properties.rb
|
@@ -46,16 +49,13 @@ files:
|
|
46
49
|
- lib/caruby/domain/resource_attributes.rb
|
47
50
|
- lib/caruby/domain/resource_dependency.rb
|
48
51
|
- lib/caruby/domain/resource_introspection.rb
|
52
|
+
- lib/caruby/domain/resource_inverse.rb
|
49
53
|
- lib/caruby/domain/resource_metadata.rb
|
50
54
|
- lib/caruby/domain/resource_module.rb
|
51
55
|
- lib/caruby/domain/uniquify.rb
|
52
|
-
- lib/caruby/import/annotatable_class.rb
|
53
|
-
- lib/caruby/import/annotation_class.rb
|
54
|
-
- lib/caruby/import/annotation_module.rb
|
55
56
|
- lib/caruby/import/java.rb
|
56
57
|
- lib/caruby/migration/migratable.rb
|
57
58
|
- lib/caruby/migration/migrator.rb
|
58
|
-
- lib/caruby/migration/resource.rb
|
59
59
|
- lib/caruby/migration/resource_module.rb
|
60
60
|
- lib/caruby/migration/uniquify.rb
|
61
61
|
- lib/caruby/util/attribute_path.rb
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/caruby/util/version.rb
|
87
87
|
- lib/caruby/util/visitor.rb
|
88
88
|
- lib/caruby/util/weak_hash.rb
|
89
|
+
- lib/caruby/yard/resource_metadata_handler.rb
|
89
90
|
- History.txt
|
90
91
|
- LEGAL
|
91
92
|
- LICENSE
|
@@ -1,131 +0,0 @@
|
|
1
|
-
require 'caruby/util/collection'
|
2
|
-
require 'caruby/util/pretty_print'
|
3
|
-
require 'caruby/domain/reference_visitor'
|
4
|
-
require 'caruby/database/fetched_matcher'
|
5
|
-
require 'caruby/database/store_template_builder'
|
6
|
-
|
7
|
-
module CaRuby
|
8
|
-
class Database
|
9
|
-
# Merges database content sources into saved targets.
|
10
|
-
class SavedMerger
|
11
|
-
# @param [Database] database the database performing the save
|
12
|
-
def initialize(database)
|
13
|
-
@database = database
|
14
|
-
# the save result matchers
|
15
|
-
cr_mtchr = FetchedMatcher.new(:relaxed)
|
16
|
-
upd_mtchr = FetchedMatcher.new
|
17
|
-
# the save result merge visitors
|
18
|
-
@cr_mrg_vstr = MergeVisitor.new(:matcher => cr_mtchr) { |src, tgt| mergeable_saved_attributes(tgt) }
|
19
|
-
@upd_mrg_vstr = MergeVisitor.new(:matcher => upd_mtchr) { |src, tgt| mergeable_saved_attributes(tgt) }
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
# Merges the database content into the given saved domain object.
|
24
|
-
# Dependents are merged recursively.
|
25
|
-
#
|
26
|
-
# @param [Resource] obj the saved domain object
|
27
|
-
# @param [Resource] result the caCORE result
|
28
|
-
# @return [Resource] the object representing the persistent state
|
29
|
-
def merge(saved, result)
|
30
|
-
# the sync source reflecting the database content
|
31
|
-
src = saved_source(saved, result)
|
32
|
-
# merge the source into obj, including all cascaded dependents
|
33
|
-
merge_saved(saved, src)
|
34
|
-
src
|
35
|
-
end
|
36
|
-
|
37
|
-
# @param [Resource] obj the saved domain object
|
38
|
-
# @param [Resource] result the caCORE result domain object
|
39
|
-
# @return [Resource] the source domain object which accurately reflects the database state
|
40
|
-
# @see #fetch_saved?
|
41
|
-
def saved_source(obj, result)
|
42
|
-
# The true stored content might need to be fetched from the database.
|
43
|
-
if obj.fetch_saved? then
|
44
|
-
tmpl = result.copy(:identifier)
|
45
|
-
logger.debug { "Fetching saved #{obj.qp} using template #{tmpl}..." }
|
46
|
-
tmpl.find
|
47
|
-
else
|
48
|
-
result
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Merges the content of the source domain object into the saved domain object obj.
|
53
|
-
# If obj differs from source, then obj is resaved. Dependents are merged recursively.
|
54
|
-
#
|
55
|
-
# @param [Resource] obj the saved domain object
|
56
|
-
# @param [Resource] source object holding the stored content
|
57
|
-
def merge_saved(obj, source)
|
58
|
-
logger.debug { "Merging database content #{source} into saved #{obj.qp}..." }
|
59
|
-
visitor = @database.mergeable_autogenerated_operation? ? @cr_mrg_vstr : @upd_mrg_vstr
|
60
|
-
visitor.visit(obj, source) do |tgt, src|
|
61
|
-
logger.debug { "Saved #{obj.qp} merge visitor merged database content #{src.qp} into #{tgt.qp}..." }
|
62
|
-
merge_saved_reference(tgt, src)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Sets the target snapshot attribute values from the given source, if different.
|
67
|
-
#
|
68
|
-
# @param [Resource] target the saved domain object
|
69
|
-
# @param [Resource] source the domain object reflecting the database state
|
70
|
-
# @return [Resource] the synced target
|
71
|
-
def merge_saved_reference(target, source)
|
72
|
-
# set each unsaved non-domain attribute from the source to reflect the database value
|
73
|
-
target.copy_volatile_attributes(source)
|
74
|
-
|
75
|
-
# take a snapshot of the saved target
|
76
|
-
target.take_snapshot
|
77
|
-
logger.debug { "A snapshot was taken of the saved #{target.qp}." }
|
78
|
-
|
79
|
-
# the non-domain attribute => [target value, source value] difference hash
|
80
|
-
diff = target.diff(source)
|
81
|
-
# the difference attribute => source value hash, excluding nil source values
|
82
|
-
dvh = diff.transform { |vdiff| vdiff.last }.compact
|
83
|
-
return if dvh.empty?
|
84
|
-
logger.debug { "Saved #{target} differs from database content #{source.qp} as follows: #{diff.filter_on_key { |attr| dvh.has_key?(attr) }.qp}" }
|
85
|
-
logger.debug { "Setting saved #{target.qp} snapshot values from source values to reflect the database state: #{dvh.qp}..." }
|
86
|
-
# update the snapshot from the source value to reflect the database state
|
87
|
-
target.snapshot.merge!(dvh)
|
88
|
-
|
89
|
-
target
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns the dependent attributes that can be copied from a save result to
|
93
|
-
# the given save argument object. This method qualifies the obj class
|
94
|
-
# {AttributeMetadata#copyable_saved_attributes} by whether the attribute is
|
95
|
-
# actually auto-generated for the saved object, i.e. the object was itself
|
96
|
-
# created or auto-generated. If obj was created or auto-generated, then
|
97
|
-
# this method returns the {AttributeMetadata#copyable_saved_attributes}.
|
98
|
-
# Otherwise, this method returns the {AttributeMetadata#cascaded_attributes}.
|
99
|
-
#
|
100
|
-
# @param [Resource] obj the domain object which was saved
|
101
|
-
# @return [<Symbol>] the attributes to copy
|
102
|
-
def mergeable_saved_attributes(obj)
|
103
|
-
fa = obj.class.fetched_domain_attributes
|
104
|
-
obj.suspend_lazy_loader do
|
105
|
-
attrs = obj.class.cascaded_attributes.filter do |attr|
|
106
|
-
fa.include?(attr) or not obj.send(attr).nil_or_empty?
|
107
|
-
end
|
108
|
-
if @database.mergeable_autogenerated_operation? then
|
109
|
-
ag_attrs = mergeable_saved_autogenerated_attributes(obj)
|
110
|
-
unless ag_attrs.empty? then
|
111
|
-
logger.debug { "Adding #{obj.qp} mergeable saved auto-generated #{ag_attrs.to_series} to the merge set..." }
|
112
|
-
attrs = attrs.to_set.merge(ag_attrs)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
logger.debug { "Mergeable saved #{obj.qp} attributes: #{attrs.qp}." } unless attrs.empty?
|
116
|
-
attrs
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# Returns the autogenerated dependent attributes that can be copied from a save result to
|
121
|
-
# the given save argument object.
|
122
|
-
#
|
123
|
-
# @param [Resource] obj the domain object which was saved
|
124
|
-
# @return [<Symbol>] the attributes to copy, or nil if no such attributes
|
125
|
-
def mergeable_saved_autogenerated_attributes(obj)
|
126
|
-
attrs = obj.class.mergeable_saved_autogenerated_attributes
|
127
|
-
attrs.reject { |attr| obj.send(attr).nil_or_empty? }
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'caruby/resource'
|
2
|
-
|
3
|
-
module CaRuby
|
4
|
-
# The Annotatable module marks a domain class as an anchor which holds at least one annotation attribute.
|
5
|
-
module Annotatable
|
6
|
-
include Resource
|
7
|
-
|
8
|
-
# Dynamically creates a new annotation reference method with the given symbol if symbol is the camelized form of a
|
9
|
-
# class in one of the Annotatable class's annotation modules.
|
10
|
-
def method_missing(symbol, *args)
|
11
|
-
name = symbol.to_s
|
12
|
-
# remove trailing assignment = if present
|
13
|
-
name.chop! if name =~ /=$/
|
14
|
-
# the class with the camelized form of the name
|
15
|
-
klass = self.class.annotation_class(name.camelize)
|
16
|
-
# delegate to super to print an error if no class
|
17
|
-
super if klass.nil?
|
18
|
-
# add the annotation attribute
|
19
|
-
klass.add_annotation(self.class)
|
20
|
-
raise NotImplementedError.new("#{self.class.qp} annotation method not created: #{symbol}") unless respond_to?(symbol)
|
21
|
-
#call the annotation attribute method
|
22
|
-
send(symbol, *args)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'caruby/resource'
|
2
|
-
|
3
|
-
module CaRuby
|
4
|
-
# The Annotation module marks a domain object as an Annotation.
|
5
|
-
module Annotation
|
6
|
-
include Resource
|
7
|
-
|
8
|
-
# Dynamically creates a new annotable owner attribute with the given symbol if symbol is an annotatable owner attribute
|
9
|
-
# accessor method.
|
10
|
-
#
|
11
|
-
# @see #attribute_missing
|
12
|
-
def method_missing(symbol, *args)
|
13
|
-
name = symbol.to_s
|
14
|
-
# remove trailing assignment = if present
|
15
|
-
name.chop! if name =~ /=$/
|
16
|
-
# try to make the owner attribute
|
17
|
-
self.class.attribute_metadata(name.to_sym)
|
18
|
-
# if we reached here, then the owner was created so verify and call the new method
|
19
|
-
raise NoMethodError.new("#{name.demodulize} owner attribute #{name} created but accessor method not found: #{symbol}") unless method_defined?(symbol)
|
20
|
-
send(symbol, *args)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'caruby/util/class'
|
2
|
-
require 'caruby/util/collection'
|
3
|
-
require 'caruby/import/annotation_module'
|
4
|
-
|
5
|
-
module JavaImport
|
6
|
-
# AnnotatableClass adds Annotation modules to an annotation anchor's domain module.
|
7
|
-
module AnnotatableClass
|
8
|
-
|
9
|
-
def self.extended(klass)
|
10
|
-
klass.class_eval { include CaRuby::Annotatable }
|
11
|
-
end
|
12
|
-
|
13
|
-
def annotation_modules
|
14
|
-
@annotation_modules ||= []
|
15
|
-
end
|
16
|
-
|
17
|
-
# Creates a new AnnotationModule anchored by this class for the given package and database service.
|
18
|
-
def create_annotation_module(package, service)
|
19
|
-
annotation_modules << AnnotationModule.create_annotation_module(self, package, service)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns the class with the given unqualified name in one of this AnnotationClass's JavaImport::AnnotationModule
|
23
|
-
# modules, or nil if no such class.
|
24
|
-
def annotation_class(name)
|
25
|
-
annotation_modules.detect_value { |mod| annotation_modules.const_get(name) rescue nil }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module JavaImport
|
2
|
-
# AnnotationClass extends a domain class for an annotation class scoped by an annotation module.
|
3
|
-
# The extended class must contain the +@anchor_class+ and +@annotation_module+ instance variables.
|
4
|
-
module AnnotationClass
|
5
|
-
|
6
|
-
# Dynamically creates a new reference attribute if the given attribute symbol is the underscore
|
7
|
-
# form of this Annotation's anchor class.
|
8
|
-
#
|
9
|
-
#@param [Symbol] attribute the missing attribute
|
10
|
-
def attribute_missing(attribute)
|
11
|
-
# delegate to super to print an error if no class
|
12
|
-
super unless attribute.to_s == anchor_class.qp.underscore
|
13
|
-
# add the annotation attribute to the anchor class and the anchor attribute to this class
|
14
|
-
anchor_class.add_annotation(self)
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [Class] the annotated class
|
18
|
-
def anchor_class
|
19
|
-
@anchor_class
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [Module] the module which scopes this AnnotationClass
|
23
|
-
def annotation_module
|
24
|
-
@annotation_module
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'caruby/util/class'
|
2
|
-
require 'caruby/util/collection'
|
3
|
-
require 'caruby/import/importable'
|
4
|
-
require 'caruby/import/annotation_class'
|
5
|
-
|
6
|
-
module JavaImport
|
7
|
-
# AnnotationModule creates annotation package modules within a domain module as a context for importing annotation classes.
|
8
|
-
module AnnotationModule
|
9
|
-
include Importable
|
10
|
-
|
11
|
-
# Creates a new AnnotationModule in the given domain_module from the given annotation package and service.
|
12
|
-
def self.create_annotation_module(anchor_class, package, service)
|
13
|
-
domain_module = anchor_class.domain_module
|
14
|
-
# make parent modules for each package component
|
15
|
-
mod = package.split('.').inject(anchor_class.domain_module) do |parent, name|
|
16
|
-
mod_id = name.camelize.to_sym
|
17
|
-
if parent.const_defined?(mod_id) then
|
18
|
-
parent.const_get(mod_id)
|
19
|
-
else
|
20
|
-
parent.const_set(mod_id, Module.new)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
# the terminal module is the AnnotationModule
|
24
|
-
mod.extend(self)
|
25
|
-
# initialize the java_package, service and empty access_properties
|
26
|
-
mod.module_eval do
|
27
|
-
@anchor_class = anchor_class
|
28
|
-
@java_package = package
|
29
|
-
@service = service
|
30
|
-
@resource_module__props = CaRuby::Domain::Properties.new
|
31
|
-
end
|
32
|
-
mod_name = mod.name[anchor_class.domain_module.name.length..-1]
|
33
|
-
logger.debug { "Created annotation module #{mod}." }
|
34
|
-
mod
|
35
|
-
end
|
36
|
-
|
37
|
-
def java_package
|
38
|
-
@java_package
|
39
|
-
end
|
40
|
-
|
41
|
-
def service
|
42
|
-
@service
|
43
|
-
end
|
44
|
-
|
45
|
-
def anchor_class
|
46
|
-
@anchor_class
|
47
|
-
end
|
48
|
-
|
49
|
-
def access_properties
|
50
|
-
@resource_module__props
|
51
|
-
end
|
52
|
-
|
53
|
-
# Imports the domain Java class with specified class_name by delegating to Importable and
|
54
|
-
# augmenting the importer to include CaRuby::Annotation in each imported class.
|
55
|
-
def import_domain_class(class_name)
|
56
|
-
anchor_class = @anchor_class
|
57
|
-
ann_mod = self
|
58
|
-
klass = super(class_name) do
|
59
|
-
include CaRuby::Annotation
|
60
|
-
@anchor_class = anchor_class
|
61
|
-
@annotation_module = ann_mod
|
62
|
-
yield if block_given?
|
63
|
-
end
|
64
|
-
klass.extend(AnnotationClass)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|