jinx 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.yardopts +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +27 -0
- data/History.md +6 -0
- data/LEGAL +5 -0
- data/LICENSE +22 -0
- data/README.md +44 -0
- data/Rakefile +41 -0
- data/examples/family/README.md +10 -0
- data/examples/family/ext/build.xml +35 -0
- data/examples/family/ext/src/family/Address.java +68 -0
- data/examples/family/ext/src/family/Child.java +24 -0
- data/examples/family/ext/src/family/DomainObject.java +26 -0
- data/examples/family/ext/src/family/Household.java +36 -0
- data/examples/family/ext/src/family/Parent.java +48 -0
- data/examples/family/ext/src/family/Person.java +42 -0
- data/examples/family/lib/family.rb +15 -0
- data/examples/family/lib/family/address.rb +6 -0
- data/examples/family/lib/family/domain_object.rb +6 -0
- data/examples/family/lib/family/household.rb +6 -0
- data/examples/family/lib/family/parent.rb +16 -0
- data/examples/family/lib/family/person.rb +6 -0
- data/examples/model/README.md +25 -0
- data/examples/model/ext/build.xml +35 -0
- data/examples/model/ext/src/domain/Child.java +192 -0
- data/examples/model/ext/src/domain/Dependent.java +29 -0
- data/examples/model/ext/src/domain/DomainObject.java +26 -0
- data/examples/model/ext/src/domain/Independent.java +83 -0
- data/examples/model/ext/src/domain/Parent.java +129 -0
- data/examples/model/ext/src/domain/Person.java +14 -0
- data/examples/model/lib/model.rb +13 -0
- data/examples/model/lib/model/child.rb +13 -0
- data/examples/model/lib/model/domain_object.rb +6 -0
- data/examples/model/lib/model/independent.rb +11 -0
- data/examples/model/lib/model/parent.rb +17 -0
- data/jinx.gemspec +22 -0
- data/lib/jinx.rb +3 -0
- data/lib/jinx/active_support/README.txt +2 -0
- data/lib/jinx/active_support/core_ext/string.rb +7 -0
- data/lib/jinx/active_support/core_ext/string/inflections.rb +167 -0
- data/lib/jinx/active_support/inflections.rb +55 -0
- data/lib/jinx/active_support/inflector.rb +398 -0
- data/lib/jinx/cli/application.rb +36 -0
- data/lib/jinx/cli/command.rb +214 -0
- data/lib/jinx/helpers/array.rb +108 -0
- data/lib/jinx/helpers/boolean.rb +42 -0
- data/lib/jinx/helpers/case_insensitive_hash.rb +39 -0
- data/lib/jinx/helpers/class.rb +149 -0
- data/lib/jinx/helpers/collection.rb +33 -0
- data/lib/jinx/helpers/collections.rb +11 -0
- data/lib/jinx/helpers/collector.rb +20 -0
- data/lib/jinx/helpers/conditional_enumerator.rb +21 -0
- data/lib/jinx/helpers/enumerable.rb +242 -0
- data/lib/jinx/helpers/enumerate.rb +35 -0
- data/lib/jinx/helpers/error.rb +15 -0
- data/lib/jinx/helpers/file_separator.rb +65 -0
- data/lib/jinx/helpers/filter.rb +52 -0
- data/lib/jinx/helpers/flattener.rb +38 -0
- data/lib/jinx/helpers/hash.rb +12 -0
- data/lib/jinx/helpers/hashable.rb +502 -0
- data/lib/jinx/helpers/inflector.rb +36 -0
- data/lib/jinx/helpers/key_transformer_hash.rb +43 -0
- data/lib/jinx/helpers/lazy_hash.rb +44 -0
- data/lib/jinx/helpers/log.rb +106 -0
- data/lib/jinx/helpers/math.rb +12 -0
- data/lib/jinx/helpers/merge.rb +60 -0
- data/lib/jinx/helpers/module.rb +18 -0
- data/lib/jinx/helpers/multi_enumerator.rb +31 -0
- data/lib/jinx/helpers/options.rb +92 -0
- data/lib/jinx/helpers/os.rb +19 -0
- data/lib/jinx/helpers/partial_order.rb +37 -0
- data/lib/jinx/helpers/pretty_print.rb +207 -0
- data/lib/jinx/helpers/set.rb +8 -0
- data/lib/jinx/helpers/stopwatch.rb +76 -0
- data/lib/jinx/helpers/transformer.rb +24 -0
- data/lib/jinx/helpers/transitive_closure.rb +55 -0
- data/lib/jinx/helpers/uniquifier.rb +50 -0
- data/lib/jinx/helpers/validation.rb +33 -0
- data/lib/jinx/helpers/visitor.rb +370 -0
- data/lib/jinx/import/class_path_modifier.rb +77 -0
- data/lib/jinx/import/java.rb +337 -0
- data/lib/jinx/importer.rb +240 -0
- data/lib/jinx/metadata.rb +155 -0
- data/lib/jinx/metadata/attribute_enumerator.rb +73 -0
- data/lib/jinx/metadata/dependency.rb +244 -0
- data/lib/jinx/metadata/id_alias.rb +23 -0
- data/lib/jinx/metadata/introspector.rb +179 -0
- data/lib/jinx/metadata/inverse.rb +170 -0
- data/lib/jinx/metadata/java_property.rb +169 -0
- data/lib/jinx/metadata/propertied.rb +500 -0
- data/lib/jinx/metadata/property.rb +401 -0
- data/lib/jinx/metadata/property_characteristics.rb +114 -0
- data/lib/jinx/resource.rb +862 -0
- data/lib/jinx/resource/copy_visitor.rb +36 -0
- data/lib/jinx/resource/inversible.rb +90 -0
- data/lib/jinx/resource/match_visitor.rb +180 -0
- data/lib/jinx/resource/matcher.rb +20 -0
- data/lib/jinx/resource/merge_visitor.rb +73 -0
- data/lib/jinx/resource/mergeable.rb +185 -0
- data/lib/jinx/resource/reference_enumerator.rb +49 -0
- data/lib/jinx/resource/reference_path_visitor.rb +38 -0
- data/lib/jinx/resource/reference_visitor.rb +55 -0
- data/lib/jinx/resource/unique.rb +35 -0
- data/lib/jinx/version.rb +3 -0
- data/spec/defaults_spec.rb +30 -0
- data/spec/definitions/model/alias/child.rb +5 -0
- data/spec/definitions/model/base/child.rb +5 -0
- data/spec/definitions/model/base/domain_object.rb +5 -0
- data/spec/definitions/model/base/independent.rb +5 -0
- data/spec/definitions/model/defaults/child.rb +5 -0
- data/spec/definitions/model/dependency/child.rb +5 -0
- data/spec/definitions/model/dependency/parent.rb +6 -0
- data/spec/definitions/model/inverse/child.rb +5 -0
- data/spec/definitions/model/inverse/independent.rb +5 -0
- data/spec/definitions/model/inverse/parent.rb +5 -0
- data/spec/definitions/model/mandatory/child.rb +6 -0
- data/spec/dependency_spec.rb +47 -0
- data/spec/family_spec.rb +64 -0
- data/spec/inverse_spec.rb +53 -0
- data/spec/mandatory_spec.rb +43 -0
- data/spec/metadata_spec.rb +68 -0
- data/spec/resource_spec.rb +30 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/model.rb +19 -0
- data/test/fixtures/line_separator/cr_line_sep.txt +1 -0
- data/test/fixtures/line_separator/crlf_line_sep.txt +3 -0
- data/test/fixtures/line_separator/lf_line_sep.txt +3 -0
- data/test/fixtures/mixed/ext/build.xml +35 -0
- data/test/fixtures/mixed/ext/src/mixed/Case/Example.java +5 -0
- data/test/helper.rb +7 -0
- data/test/lib/jinx/command_test.rb +41 -0
- data/test/lib/jinx/helpers/boolean_test.rb +27 -0
- data/test/lib/jinx/helpers/class_test.rb +60 -0
- data/test/lib/jinx/helpers/collections_test.rb +402 -0
- data/test/lib/jinx/helpers/file_separator_test.rb +29 -0
- data/test/lib/jinx/helpers/inflector_test.rb +11 -0
- data/test/lib/jinx/helpers/lazy_hash_test.rb +32 -0
- data/test/lib/jinx/helpers/module_test.rb +24 -0
- data/test/lib/jinx/helpers/options_test.rb +66 -0
- data/test/lib/jinx/helpers/partial_order_test.rb +41 -0
- data/test/lib/jinx/helpers/pretty_print_test.rb +83 -0
- data/test/lib/jinx/helpers/stopwatch_test.rb +16 -0
- data/test/lib/jinx/helpers/transitive_closure_test.rb +80 -0
- data/test/lib/jinx/helpers/visitor_test.rb +288 -0
- data/test/lib/jinx/import/java_test.rb +78 -0
- data/test/lib/jinx/import/mixed_case_test.rb +16 -0
- metadata +272 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
require 'generator'
|
3
|
+
require 'jinx/helpers/options'
|
4
|
+
require 'jinx/helpers/collections'
|
5
|
+
|
6
|
+
require 'jinx/helpers/validation'
|
7
|
+
require 'jinx/helpers/visitor'
|
8
|
+
require 'jinx/helpers/math'
|
9
|
+
|
10
|
+
module Jinx
|
11
|
+
# A ReferenceEnumerator iterates over domain property references.
|
12
|
+
class ReferenceEnumerator
|
13
|
+
include Enumerable
|
14
|
+
|
15
|
+
# @return [Resource] the domain object containing the references
|
16
|
+
attr_reader :subject
|
17
|
+
|
18
|
+
alias :on :subject
|
19
|
+
|
20
|
+
alias :from :subject
|
21
|
+
|
22
|
+
# @return [<Property>] the current property
|
23
|
+
attr_reader :property
|
24
|
+
|
25
|
+
# @param [Resource, nil] on the object containing the references
|
26
|
+
# @param [<Property>, Property, nil] properties the property or properties to dereference
|
27
|
+
def initialize(on=nil, properties=nil)
|
28
|
+
@subject = on
|
29
|
+
@properties = properties
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param [Resource] obj the visiting domain object
|
33
|
+
# @return [(Resource, Resource, Property)] the (visited, visiting, property) tuples
|
34
|
+
# @yield [obj, from, property] operates on the visited domain object
|
35
|
+
# @yieldparam [Resource] obj the visited domain object
|
36
|
+
# @yieldparam [Resource] from the visiting domain object
|
37
|
+
# @yieldparam [Property] property the visiting property
|
38
|
+
def each
|
39
|
+
return if @subject.nil?
|
40
|
+
@properties.enumerate do |prop|
|
41
|
+
@property = prop
|
42
|
+
# the reference(s) to visit
|
43
|
+
refs = @subject.send(prop.attribute)
|
44
|
+
# associate each reference to visit with the current visited attribute
|
45
|
+
refs.enumerate { |ref| yield(ref) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'jinx/helpers/collections'
|
2
|
+
|
3
|
+
require 'jinx/helpers/validation'
|
4
|
+
require 'jinx/helpers/visitor'
|
5
|
+
require 'jinx/helpers/math'
|
6
|
+
|
7
|
+
module Jinx
|
8
|
+
# A ReferencePathVisitor traverses an attribute path.
|
9
|
+
#
|
10
|
+
# For example, given the attributes:
|
11
|
+
# favorites : Person -> Book
|
12
|
+
# authors : Book -> Author
|
13
|
+
# publications : Author -> Book
|
14
|
+
# then a path visitor given by:
|
15
|
+
# ReferencePathVisitor.new(Person, [:favorites, :authors, :publications])
|
16
|
+
# visits the transitive closure of books published by the authors of a person's favorite books.
|
17
|
+
class ReferencePathVisitor < ReferenceVisitor
|
18
|
+
# @return [ReferenceVisitor] a visitor which traverses the given path attributes starting at
|
19
|
+
# an instance of the given type
|
20
|
+
#
|
21
|
+
# @param [Class] the type of object to begin the traversal
|
22
|
+
# @param [<Symbol>] the attributes to traverse
|
23
|
+
# @param opts (see ReferenceVisitor#initialize)
|
24
|
+
def initialize(klass, attributes, opts=nil)
|
25
|
+
# augment the attributes path as a [class, attribute] path
|
26
|
+
path = klass.property_path(*attributes)
|
27
|
+
# make the visitor
|
28
|
+
super(opts) do |ref|
|
29
|
+
# Collect the path attributes whose type is the ref type up to the
|
30
|
+
# next position in the path.
|
31
|
+
max = lineage.size.min(path.size)
|
32
|
+
pas = (0...max).map { |i| path[i].attribute if path[i].declarer === ref }
|
33
|
+
pas.compact!
|
34
|
+
ref.class.attribute_filter(pas)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
require 'generator'
|
3
|
+
require 'jinx/helpers/options'
|
4
|
+
require 'jinx/helpers/collections'
|
5
|
+
|
6
|
+
require 'jinx/helpers/validation'
|
7
|
+
require 'jinx/helpers/visitor'
|
8
|
+
require 'jinx/helpers/math'
|
9
|
+
|
10
|
+
module Jinx
|
11
|
+
# A ReferenceVisitor traverses reference attributes.
|
12
|
+
class ReferenceVisitor < Visitor
|
13
|
+
# Creates a new ReferenceVisitor on domain reference attributes.
|
14
|
+
#
|
15
|
+
# The required selector block given to this initializer determines which attributes to
|
16
|
+
# visit. The references to visit next thus consist of the current domain object's selector
|
17
|
+
# attributes' values. If the :filter option is set, then the given filter block is applied
|
18
|
+
# to the selected attribute references to restrict which domain objects will be visited.
|
19
|
+
#
|
20
|
+
# @param opts (see Visitor#initialize)
|
21
|
+
# @option opts [Proc] :filter an optional filter on the references to visit
|
22
|
+
# @yield [obj] returns the {AttributeEnumerator} of attributes to visit next from the
|
23
|
+
# current domain object
|
24
|
+
# @yieldparam [Resource] obj the current domain object
|
25
|
+
def initialize(opts=nil, &selector)
|
26
|
+
Jinx.fail(ArgumentError, "Reference visitor missing domain reference selector") unless block_given?
|
27
|
+
# the property selector
|
28
|
+
@flt_sel = selector
|
29
|
+
# the reference filter
|
30
|
+
flt = Options.get(:filter, opts)
|
31
|
+
# Initialize the Visitor with a reference enumerator which selects the reference
|
32
|
+
# attributes and applies the optional filter if necessary.
|
33
|
+
@ref_enums = {}
|
34
|
+
super do |ref|
|
35
|
+
# the reference property filter
|
36
|
+
attrs = attributes_to_visit(ref)
|
37
|
+
if attrs then
|
38
|
+
logger.debug { "#{qp} visiting #{ref} attributes #{attrs.pp_s(:single_line)}..." } if @verbose
|
39
|
+
# an enumerator on the reference properties
|
40
|
+
enum = ReferenceEnumerator.new(ref, attrs.properties)
|
41
|
+
# If there is a reference filter, then apply it to the enum references.
|
42
|
+
flt ? enum.filter(&flt) : enum
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @param [Resource] obj the visiting object
|
50
|
+
# @return [Propertied::Filter] the attributes to visit
|
51
|
+
def attributes_to_visit(obj)
|
52
|
+
@flt_sel.call(obj)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'jinx/helpers/uniquifier'
|
2
|
+
|
3
|
+
module Jinx
|
4
|
+
# The Unique mix-in makes values unique within the scope of a Resource class.
|
5
|
+
module Unique
|
6
|
+
# Makes the given String value unique in the context of this object's class.
|
7
|
+
# @return nil if value is nil
|
8
|
+
# Raises TypeError if value is neither nil nor a String.
|
9
|
+
def uniquify_value(value)
|
10
|
+
unless String === value or value.nil? then
|
11
|
+
Jinx.fail(TypeError, "Cannot uniquify #{qp} non-String value #{value}")
|
12
|
+
end
|
13
|
+
Uniquifier.instance.uniquify(self, value)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Makes the secondary key unique by replacing each String key attribute value
|
17
|
+
# with a unique value.
|
18
|
+
def uniquify
|
19
|
+
uniquify_attributes(self.class.secondary_key_attributes)
|
20
|
+
uniquify_attributes(self.class.alternate_key_attributes)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Makes the given attribute values unique by replacing each String value
|
24
|
+
# with a unique value.
|
25
|
+
def uniquify_attributes(attributes)
|
26
|
+
attributes.each do |ka|
|
27
|
+
oldval = send(ka)
|
28
|
+
next unless String === oldval
|
29
|
+
newval = uniquify_value(oldval)
|
30
|
+
set_property_value(ka, newval)
|
31
|
+
logger.debug { "Reset #{qp} #{ka} from #{oldval} to unique value #{newval}." }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/jinx/version.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Model
|
4
|
+
describe 'Defaults' do
|
5
|
+
before(:all) do
|
6
|
+
Model.definitions BASE, DEFAULTS
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should recognize the property default" do
|
10
|
+
Child.defaults[:cardinal].should be 1
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should set the default property value" do
|
14
|
+
c = Child.new
|
15
|
+
c.add_defaults
|
16
|
+
c.cardinal.should be 1
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not reset a property value to the default" do
|
20
|
+
c = Child.new(:cardinal => 2)
|
21
|
+
c.add_defaults
|
22
|
+
c.cardinal.should be 2
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# The defaults fixture model definitions.
|
28
|
+
DEFAULTS = File.dirname(__FILE__) + '/definitions/model/defaults'
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Model
|
4
|
+
describe 'Dependency' do
|
5
|
+
before(:all) do
|
6
|
+
Model.definitions BASE, DEPENDENCY
|
7
|
+
end
|
8
|
+
|
9
|
+
context '1:1' do
|
10
|
+
it "should capture the dependents" do
|
11
|
+
d = Dependent.new
|
12
|
+
c = Child.new(:dependent => d)
|
13
|
+
c.dependents.should include d
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context '1:N' do
|
18
|
+
it "should set the inverses" do
|
19
|
+
Child.property(:parent).inverse.should be :children
|
20
|
+
Parent.property(:children).inverse.should be :parent
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should capture the dependents" do
|
24
|
+
p = Parent.new
|
25
|
+
c = Child.new(:parent => p)
|
26
|
+
p.dependents.should include c
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should fail to validate a missing owner" do
|
30
|
+
c = Child.new
|
31
|
+
expect { c.validate }.to raise_error(Jinx::ValidationError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should validate an existing owner" do
|
35
|
+
p = Parent.new
|
36
|
+
c = Child.new(:parent => p, :name => 'Sam')
|
37
|
+
expect { c.validate }.to_not raise_error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# The dependency fixture model definitions.
|
44
|
+
# @private
|
45
|
+
DEPENDENCY = File.dirname(__FILE__) + '/definitions/model/dependency'
|
46
|
+
end
|
47
|
+
end
|
data/spec/family_spec.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
require File.dirname(__FILE__) + '/../examples/family/lib/family'
|
3
|
+
|
4
|
+
module Family
|
5
|
+
describe DomainObject do
|
6
|
+
it "should set the primary key attribute" do
|
7
|
+
DomainObject.primary_key_attributes.should == [:identifier]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Address do
|
12
|
+
it "should have an attribute => value constructor" do
|
13
|
+
Address.new(:state => 'OR').state.should == 'OR'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should recognize an alias" do
|
17
|
+
a = Address.new(:postal_code => '95111')
|
18
|
+
a.zip.should == a.postal_code
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Parent do
|
23
|
+
it "should inherit the primary key" do
|
24
|
+
Parent.primary_key_attributes.should be DomainObject.primary_key_attributes
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have a secondary key" do
|
28
|
+
Parent.secondary_key_attributes.should == [:ssn]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should have a name property" do
|
32
|
+
Parent.property_defined?(:name).should be true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should have a children dependent" do
|
36
|
+
Parent.property(:children).dependent?.should be true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe Child do
|
41
|
+
it "should have a parents owner" do
|
42
|
+
Child.property(:parents).owner?.should be true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should add itself to the household inverse" do
|
46
|
+
h = Household.new
|
47
|
+
c = Child.new(:household => h)
|
48
|
+
h.members.should include c
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not add itself to the parents inverse" do
|
52
|
+
p = Parent.new
|
53
|
+
c = Child.new(:parents => [p])
|
54
|
+
p.children.should_not include c
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe Household do
|
59
|
+
it "should have a dependent address" do
|
60
|
+
a = Address.new
|
61
|
+
Household.new(:address => a).dependents.should include a
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Model
|
4
|
+
describe 'Inverse' do
|
5
|
+
before(:all) do
|
6
|
+
Model.definitions BASE, INVERSE
|
7
|
+
end
|
8
|
+
|
9
|
+
context '1:1' do
|
10
|
+
it "should set the inverse" do
|
11
|
+
Parent.property(:spouse).inverse.should == :spouse
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set the target inverse type back to self" do
|
15
|
+
Parent.property(:spouse).inverse.should == :spouse
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should enforce inverse integrity" do
|
19
|
+
m = Parent.new
|
20
|
+
f = Parent.new(:spouse => m)
|
21
|
+
m.spouse.should be f
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context '1:N' do
|
26
|
+
it "should set the inverse" do
|
27
|
+
Child.property(:parent).inverse.should == :children
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should set the target inverse type back to self" do
|
31
|
+
Parent.property(:children).inverse.should == :parent
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should enforce inverse integrity" do
|
35
|
+
p = Parent.new
|
36
|
+
c = Child.new(:parent => p)
|
37
|
+
p.children.should include c
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'M:N' do
|
42
|
+
it "should set the inverse" do
|
43
|
+
Independent.property(:others).inverse.should == :others
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# The inverse fixture model definitions.
|
50
|
+
# @private
|
51
|
+
INVERSE = File.dirname(__FILE__) + '/definitions/model/inverse'
|
52
|
+
end
|
53
|
+
end
|