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