jinx 2.1.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.
Files changed (149) hide show
  1. data/.gitignore +14 -0
  2. data/.rspec +3 -0
  3. data/.yardopts +1 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +27 -0
  6. data/History.md +6 -0
  7. data/LEGAL +5 -0
  8. data/LICENSE +22 -0
  9. data/README.md +44 -0
  10. data/Rakefile +41 -0
  11. data/examples/family/README.md +10 -0
  12. data/examples/family/ext/build.xml +35 -0
  13. data/examples/family/ext/src/family/Address.java +68 -0
  14. data/examples/family/ext/src/family/Child.java +24 -0
  15. data/examples/family/ext/src/family/DomainObject.java +26 -0
  16. data/examples/family/ext/src/family/Household.java +36 -0
  17. data/examples/family/ext/src/family/Parent.java +48 -0
  18. data/examples/family/ext/src/family/Person.java +42 -0
  19. data/examples/family/lib/family.rb +15 -0
  20. data/examples/family/lib/family/address.rb +6 -0
  21. data/examples/family/lib/family/domain_object.rb +6 -0
  22. data/examples/family/lib/family/household.rb +6 -0
  23. data/examples/family/lib/family/parent.rb +16 -0
  24. data/examples/family/lib/family/person.rb +6 -0
  25. data/examples/model/README.md +25 -0
  26. data/examples/model/ext/build.xml +35 -0
  27. data/examples/model/ext/src/domain/Child.java +192 -0
  28. data/examples/model/ext/src/domain/Dependent.java +29 -0
  29. data/examples/model/ext/src/domain/DomainObject.java +26 -0
  30. data/examples/model/ext/src/domain/Independent.java +83 -0
  31. data/examples/model/ext/src/domain/Parent.java +129 -0
  32. data/examples/model/ext/src/domain/Person.java +14 -0
  33. data/examples/model/lib/model.rb +13 -0
  34. data/examples/model/lib/model/child.rb +13 -0
  35. data/examples/model/lib/model/domain_object.rb +6 -0
  36. data/examples/model/lib/model/independent.rb +11 -0
  37. data/examples/model/lib/model/parent.rb +17 -0
  38. data/jinx.gemspec +22 -0
  39. data/lib/jinx.rb +3 -0
  40. data/lib/jinx/active_support/README.txt +2 -0
  41. data/lib/jinx/active_support/core_ext/string.rb +7 -0
  42. data/lib/jinx/active_support/core_ext/string/inflections.rb +167 -0
  43. data/lib/jinx/active_support/inflections.rb +55 -0
  44. data/lib/jinx/active_support/inflector.rb +398 -0
  45. data/lib/jinx/cli/application.rb +36 -0
  46. data/lib/jinx/cli/command.rb +214 -0
  47. data/lib/jinx/helpers/array.rb +108 -0
  48. data/lib/jinx/helpers/boolean.rb +42 -0
  49. data/lib/jinx/helpers/case_insensitive_hash.rb +39 -0
  50. data/lib/jinx/helpers/class.rb +149 -0
  51. data/lib/jinx/helpers/collection.rb +33 -0
  52. data/lib/jinx/helpers/collections.rb +11 -0
  53. data/lib/jinx/helpers/collector.rb +20 -0
  54. data/lib/jinx/helpers/conditional_enumerator.rb +21 -0
  55. data/lib/jinx/helpers/enumerable.rb +242 -0
  56. data/lib/jinx/helpers/enumerate.rb +35 -0
  57. data/lib/jinx/helpers/error.rb +15 -0
  58. data/lib/jinx/helpers/file_separator.rb +65 -0
  59. data/lib/jinx/helpers/filter.rb +52 -0
  60. data/lib/jinx/helpers/flattener.rb +38 -0
  61. data/lib/jinx/helpers/hash.rb +12 -0
  62. data/lib/jinx/helpers/hashable.rb +502 -0
  63. data/lib/jinx/helpers/inflector.rb +36 -0
  64. data/lib/jinx/helpers/key_transformer_hash.rb +43 -0
  65. data/lib/jinx/helpers/lazy_hash.rb +44 -0
  66. data/lib/jinx/helpers/log.rb +106 -0
  67. data/lib/jinx/helpers/math.rb +12 -0
  68. data/lib/jinx/helpers/merge.rb +60 -0
  69. data/lib/jinx/helpers/module.rb +18 -0
  70. data/lib/jinx/helpers/multi_enumerator.rb +31 -0
  71. data/lib/jinx/helpers/options.rb +92 -0
  72. data/lib/jinx/helpers/os.rb +19 -0
  73. data/lib/jinx/helpers/partial_order.rb +37 -0
  74. data/lib/jinx/helpers/pretty_print.rb +207 -0
  75. data/lib/jinx/helpers/set.rb +8 -0
  76. data/lib/jinx/helpers/stopwatch.rb +76 -0
  77. data/lib/jinx/helpers/transformer.rb +24 -0
  78. data/lib/jinx/helpers/transitive_closure.rb +55 -0
  79. data/lib/jinx/helpers/uniquifier.rb +50 -0
  80. data/lib/jinx/helpers/validation.rb +33 -0
  81. data/lib/jinx/helpers/visitor.rb +370 -0
  82. data/lib/jinx/import/class_path_modifier.rb +77 -0
  83. data/lib/jinx/import/java.rb +337 -0
  84. data/lib/jinx/importer.rb +240 -0
  85. data/lib/jinx/metadata.rb +155 -0
  86. data/lib/jinx/metadata/attribute_enumerator.rb +73 -0
  87. data/lib/jinx/metadata/dependency.rb +244 -0
  88. data/lib/jinx/metadata/id_alias.rb +23 -0
  89. data/lib/jinx/metadata/introspector.rb +179 -0
  90. data/lib/jinx/metadata/inverse.rb +170 -0
  91. data/lib/jinx/metadata/java_property.rb +169 -0
  92. data/lib/jinx/metadata/propertied.rb +500 -0
  93. data/lib/jinx/metadata/property.rb +401 -0
  94. data/lib/jinx/metadata/property_characteristics.rb +114 -0
  95. data/lib/jinx/resource.rb +862 -0
  96. data/lib/jinx/resource/copy_visitor.rb +36 -0
  97. data/lib/jinx/resource/inversible.rb +90 -0
  98. data/lib/jinx/resource/match_visitor.rb +180 -0
  99. data/lib/jinx/resource/matcher.rb +20 -0
  100. data/lib/jinx/resource/merge_visitor.rb +73 -0
  101. data/lib/jinx/resource/mergeable.rb +185 -0
  102. data/lib/jinx/resource/reference_enumerator.rb +49 -0
  103. data/lib/jinx/resource/reference_path_visitor.rb +38 -0
  104. data/lib/jinx/resource/reference_visitor.rb +55 -0
  105. data/lib/jinx/resource/unique.rb +35 -0
  106. data/lib/jinx/version.rb +3 -0
  107. data/spec/defaults_spec.rb +30 -0
  108. data/spec/definitions/model/alias/child.rb +5 -0
  109. data/spec/definitions/model/base/child.rb +5 -0
  110. data/spec/definitions/model/base/domain_object.rb +5 -0
  111. data/spec/definitions/model/base/independent.rb +5 -0
  112. data/spec/definitions/model/defaults/child.rb +5 -0
  113. data/spec/definitions/model/dependency/child.rb +5 -0
  114. data/spec/definitions/model/dependency/parent.rb +6 -0
  115. data/spec/definitions/model/inverse/child.rb +5 -0
  116. data/spec/definitions/model/inverse/independent.rb +5 -0
  117. data/spec/definitions/model/inverse/parent.rb +5 -0
  118. data/spec/definitions/model/mandatory/child.rb +6 -0
  119. data/spec/dependency_spec.rb +47 -0
  120. data/spec/family_spec.rb +64 -0
  121. data/spec/inverse_spec.rb +53 -0
  122. data/spec/mandatory_spec.rb +43 -0
  123. data/spec/metadata_spec.rb +68 -0
  124. data/spec/resource_spec.rb +30 -0
  125. data/spec/spec_helper.rb +3 -0
  126. data/spec/support/model.rb +19 -0
  127. data/test/fixtures/line_separator/cr_line_sep.txt +1 -0
  128. data/test/fixtures/line_separator/crlf_line_sep.txt +3 -0
  129. data/test/fixtures/line_separator/lf_line_sep.txt +3 -0
  130. data/test/fixtures/mixed/ext/build.xml +35 -0
  131. data/test/fixtures/mixed/ext/src/mixed/Case/Example.java +5 -0
  132. data/test/helper.rb +7 -0
  133. data/test/lib/jinx/command_test.rb +41 -0
  134. data/test/lib/jinx/helpers/boolean_test.rb +27 -0
  135. data/test/lib/jinx/helpers/class_test.rb +60 -0
  136. data/test/lib/jinx/helpers/collections_test.rb +402 -0
  137. data/test/lib/jinx/helpers/file_separator_test.rb +29 -0
  138. data/test/lib/jinx/helpers/inflector_test.rb +11 -0
  139. data/test/lib/jinx/helpers/lazy_hash_test.rb +32 -0
  140. data/test/lib/jinx/helpers/module_test.rb +24 -0
  141. data/test/lib/jinx/helpers/options_test.rb +66 -0
  142. data/test/lib/jinx/helpers/partial_order_test.rb +41 -0
  143. data/test/lib/jinx/helpers/pretty_print_test.rb +83 -0
  144. data/test/lib/jinx/helpers/stopwatch_test.rb +16 -0
  145. data/test/lib/jinx/helpers/transitive_closure_test.rb +80 -0
  146. data/test/lib/jinx/helpers/visitor_test.rb +288 -0
  147. data/test/lib/jinx/import/java_test.rb +78 -0
  148. data/test/lib/jinx/import/mixed_case_test.rb +16 -0
  149. metadata +272 -0
@@ -0,0 +1,43 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ module Model
4
+ describe 'Mandatory' do
5
+ before(:all) do
6
+ Model.definitions BASE, MANDATORY
7
+ end
8
+
9
+ it "should recognize the mandatory property" do
10
+ Child.property(:flag).mandatory?.should be true
11
+ end
12
+
13
+ it "should fail to validate a missing mandatory property value" do
14
+ c = Child.new
15
+ expect { c.validate }.to raise_error(Jinx::ValidationError)
16
+ end
17
+
18
+ it "should validate an existing mandatory property value" do
19
+ c = Child.new(:name => 'Sam')
20
+ c.flag = true
21
+ expect { c.validate }.to_not raise_error
22
+ end
23
+
24
+ it "should validate a mandatory property set to false" do
25
+ c = Child.new(:name => 'Sam')
26
+ c.flag = false
27
+ expect { c.validate }.to_not raise_error
28
+ end
29
+
30
+ it "should not revalidate a property" do
31
+ c = Child.new(:name => 'Sam')
32
+ c.flag = true
33
+ expect { c.validate }.to_not raise_error
34
+ c.flag = nil
35
+ expect { c.validate }.to_not raise_error
36
+ end
37
+
38
+ private
39
+
40
+ # The defaults fixture model definitions.
41
+ MANDATORY = File.dirname(__FILE__) + '/definitions/model/mandatory'
42
+ end
43
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ module Model
4
+ describe 'Metadata' do
5
+ before(:all) do
6
+ Model.definitions BASE, ALIAS
7
+ end
8
+
9
+ it "should import a resource class" do
10
+ Parent.should be < Jinx::Resource
11
+ end
12
+
13
+ it "should import a resource superclass in the same package" do
14
+ Child.superclass.should be < Jinx::Resource
15
+ Child.superclass.superclass.should_not be < Jinx::Resource
16
+ end
17
+
18
+ it "should introspect the properties" do
19
+ expect { Child.property(:cardinal) }.to_not raise_error
20
+ end
21
+
22
+ it "should alias the reserved id attribute" do
23
+ Child.attributes.should include :identifier
24
+ Child.attributes.should_not include :id
25
+ end
26
+
27
+ it "should set the collection property flag" do
28
+ Parent.property(:children).collection?.should be true
29
+ end
30
+
31
+ it "should set the collection property type" do
32
+ Independent.property(:others).type.should be Independent
33
+ end
34
+
35
+ it "should infer the collection property type" do
36
+ Parent.property(:children).type.should be Child
37
+ end
38
+
39
+ it "should make an empty collection value" do
40
+ Parent.empty_value(:children).class.should < Java::JavaUtil::Collection
41
+ end
42
+
43
+ it "should recognize a domain property type" do
44
+ Parent.domain_type(:children).should be Child
45
+ Child.domain_type(:cardinal).should be nil
46
+ end
47
+
48
+ it "should recognize a property alias" do
49
+ Child.property(:pals).should be Child.property(:friends)
50
+ end
51
+
52
+ it "should set the primary key" do
53
+ DomainObject.primary_key_attributes.should == [:identifier]
54
+ end
55
+
56
+ it "should inherit the primary key" do
57
+ Child.primary_key_attributes.should be DomainObject.primary_key_attributes
58
+ end
59
+
60
+ it "should set the secondary key" do
61
+ Child.secondary_key_attributes.should == [:name]
62
+ end
63
+
64
+ private
65
+
66
+ ALIAS = File.dirname(__FILE__) + '/definitions/model/alias'
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ module Model
4
+ describe 'Resource' do
5
+ before(:all) do
6
+ Model.definitions BASE
7
+ end
8
+
9
+ it "should have a resource attribute => value constructor" do
10
+ Child.new(:name => 'Test').name.should == 'Test'
11
+ end
12
+
13
+ it "should merge an attribute => value hash" do
14
+ c = Child.new(:name => 'Test')
15
+ p = Parent.new
16
+ c.merge({:name => 'Other', :cardinal => 1, :parent => p})
17
+ c.name.should == 'Test'
18
+ c.cardinal.should be 1
19
+ c.parent.should be p
20
+ end
21
+
22
+ it "should merge another resource" do
23
+ c = Child.new(:name => 'Test')
24
+ other = Child.new(:name => 'Other', :cardinal => 1)
25
+ c.merge(other)
26
+ c.name.should == 'Test'
27
+ c.cardinal.should be 1
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/../test/helper'
2
+
3
+ Dir.glob(File.dirname(__FILE__) + '/support/**/*.rb').each { |f| require f }
@@ -0,0 +1,19 @@
1
+ # Add the Java jar file to the Java path.
2
+ require File.dirname(__FILE__) + '/../../examples/model/ext/bin/model.jar'
3
+
4
+ # The Jinx Model example application domain module.
5
+ module Model
6
+ include Jinx::Resource
7
+
8
+ extend Jinx::Importer
9
+
10
+ # The Java package name.
11
+ packages 'domain'
12
+
13
+ # expose the definitions for testing
14
+ public_class_method :definitions
15
+
16
+ # The base fixture model definitions.
17
+ BASE = File.dirname(__FILE__) + '/../definitions/model/base'
18
+ end
19
+
@@ -0,0 +1,35 @@
1
+ <?xml version ="1.0"?>
2
+
3
+ <project name="import Jinx test fixture" default="jar">
4
+
5
+ <!--build locations -->
6
+ <property name="base.dir" value="." />
7
+ <property name="source.dir" value="src" />
8
+ <property name="target.dir" value="classes" />
9
+ <property name="bin.dir" value="bin" />
10
+
11
+ <target name="init">
12
+ <tstamp />
13
+ <mkdir dir="${target.dir}" />
14
+ <mkdir dir="${bin.dir}" />
15
+ </target>
16
+
17
+ <!-- Compile all files in the source directory -->
18
+ <target name="compile" depends="init">
19
+ <javac destdir="${target.dir}" includes="**/*.*">
20
+ <src path="${source.dir}" />
21
+ <compilerarg value="-Xlint:unchecked"/>
22
+ </javac>
23
+ </target>
24
+
25
+ <target name="jar" depends="compile">
26
+ <jar destfile="${bin.dir}/mixed_case.jar" basedir="${target.dir}" includes="**/*.*" />
27
+ </target>
28
+
29
+ <!-- Remove build directories -->
30
+ <target name="clean">
31
+ <delete dir="${bin.dir}" />
32
+ <delete dir="${target.dir}" />
33
+ </target>
34
+
35
+ </project>
@@ -0,0 +1,5 @@
1
+ package mixed.Case;
2
+
3
+ public class Example
4
+ {
5
+ }
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler.require(:test, :development)
4
+ require 'jinx/helpers/log'
5
+
6
+ # Open the logger.
7
+ Jinx::Log.instance.open(File.dirname(__FILE__) + '/results/log/jinx.log', :debug => true)
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../../helper'
2
+ require 'test/unit'
3
+ require 'jinx/cli/command'
4
+ require 'set'
5
+
6
+ module Jinx
7
+ class CommandTest < Test::Unit::TestCase
8
+ def test_empty
9
+ verify_execution(CLI::Command.new, '', {})
10
+ end
11
+
12
+ def test_arg
13
+ verify_execution(CLI::Command.new([[:arg, 'ARG']]), '4', {:arg => '4'})
14
+ end
15
+
16
+ def test_option
17
+ verify_execution(CLI::Command.new([[:opt, '--opt N', 'option']]), '--opt 4', {:opt => '4'})
18
+ end
19
+
20
+ def test_typed_option
21
+ verify_execution(CLI::Command.new([[:opt, '--opt N', Integer, 'option']]), '--opt 4', {:opt => 4})
22
+ end
23
+
24
+ def test_both
25
+ verify_execution(CLI::Command.new([[:arg, 'ARG'], [:opt, '--opt N', 'option']]), '4 --opt 5', {:arg => '4', :opt => '5'})
26
+ end
27
+
28
+ private
29
+
30
+ def verify_execution(cmd, s, expected)
31
+ ARGV.clear.concat(s.split)
32
+ cmd.start do |actual|
33
+ actual.each do |opt, aval|
34
+ eval = expected[opt]
35
+ assert_not_nil(aval, "Command option #{opt} not found.")
36
+ assert_equal(eval, aval, "Command option #{opt} parsed incorrectly.")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/../../../helper'
2
+ require 'test/unit'
3
+ require 'jinx/helpers/boolean'
4
+
5
+ class BooleanTest < Test::Unit::TestCase
6
+ def test_marker
7
+ assert(Jinx::Boolean === true, "true is not a Jinx::Boolean")
8
+ assert(Jinx::Boolean === false, "false is not a Jinx::Boolean")
9
+ assert(!nil.is_a?(Jinx::Boolean), "nil is a Jinx::Boolean")
10
+ end
11
+
12
+ def test_string
13
+ ['true', 'True', 't', 'T', 'yes', 'Yes', 'y', 'Y', '1'].each do |s|
14
+ assert_equal(true, Jinx::Boolean.for(s), "#{s} is not converted to true")
15
+ end
16
+ ['false', 'False', 'f', 'F', 'no', 'No', 'n', 'N', '0'].each do |s|
17
+ assert_equal(false, Jinx::Boolean.for(s), "#{s} is not converted to false")
18
+ end
19
+ assert_raises(ArgumentError, "Invalid boolean string was converted") { Jinx::Boolean.for('Maybe') }
20
+ end
21
+
22
+ def test_integer
23
+ assert_equal(true, Jinx::Boolean.for(1), "#{self} is not converted to true")
24
+ assert_equal(false, Jinx::Boolean.for(0), "#{self} is not converted to false")
25
+ assert_raises(ArgumentError, "Invalid boolean integer was converted") { Jinx::Boolean.for(3) }
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/../../../helper'
2
+ require 'test/unit'
3
+ require 'jinx/helpers/class'
4
+
5
+ class ClassTest < Test::Unit::TestCase
6
+ def ssn
7
+ '555-55-555'
8
+ end
9
+
10
+ def self.redefine_ssn
11
+ redefine_method(:ssn) { |old_method| lambda { send(old_method).delete('-').to_i } }
12
+ end
13
+
14
+ def test_redefine_method
15
+ self.class.redefine_ssn
16
+ assert_equal(55555555, ssn, "Method not redefined correctly")
17
+ end
18
+
19
+ def test_class_hierarchy
20
+ assert_equal([Array, Object], Array.class_hierarchy.to_a, "Class ancestors incorrect")
21
+ end
22
+
23
+ class Person
24
+ attr_reader :social_security_number
25
+ attr_accessor :postal_code
26
+ alias_attribute(:ssn, :social_security_number)
27
+ alias_attribute(:zip_code, :postal_code)
28
+ end
29
+
30
+ def test_attribute_alias
31
+ assert(Person.method_defined?(:ssn), "Reader alias not defined")
32
+ assert(!Person.method_defined?(:ssn=), "Writer alias incorrectly defined")
33
+ assert(Person.method_defined?(:zip_code), "Reader alias not defined")
34
+ assert(Person.method_defined?(:zip_code=), "Writer alias not defined")
35
+ end
36
+
37
+ class A; end
38
+ class B < A; end
39
+
40
+ def test_range
41
+ assert_equal([B, A, Object], (B..Object).to_a, "Class range incorrect")
42
+ end
43
+
44
+ class OneBased
45
+ attr_accessor :index
46
+ offset_attr_accessor :zero_based_index => :index
47
+ offset_attr_accessor({:two_based_index => :index}, 1)
48
+ end
49
+
50
+ def test_offset_attr_accessor
51
+ x = OneBased.new
52
+ x.index = 1
53
+ assert_equal(0, x.zero_based_index, "Offset reader incorrect")
54
+ x.zero_based_index = 1
55
+ assert_equal(2, x.index, "Offset writer incorrect")
56
+ assert_equal(3, x.two_based_index, "Offset reader incorrect")
57
+ x.two_based_index = 1
58
+ assert_equal(0, x.index, "Offset writer incorrect")
59
+ end
60
+ end
@@ -0,0 +1,402 @@
1
+ require File.dirname(__FILE__) + '/../../../helper'
2
+ require 'test/unit'
3
+ require 'jinx/helpers/collections'
4
+ require 'jinx/helpers/lazy_hash'
5
+ require 'jinx/helpers/case_insensitive_hash'
6
+ require 'jinx/helpers/key_transformer_hash'
7
+ require 'jinx/helpers/conditional_enumerator'
8
+ require 'jinx/helpers/multi_enumerator'
9
+
10
+ class CollectionsTest < Test::Unit::TestCase
11
+ def test_collection_classifier
12
+ assert([].collection?, "array is not a collecton")
13
+ assert(!nil.collection?, "nil is a collecton")
14
+ assert(!'a'.collection?, "String is a collecton")
15
+ end
16
+
17
+ def test_hashify
18
+ actual = [1, 2, 3].hashify { |key| key + 1 unless key == 2 }
19
+ expected = {1 => 2, 2 => nil, 3 => 4}
20
+ assert_equal(expected, actual, 'Hashify result incorrect')
21
+ end
22
+
23
+ def test_to_compact_hash
24
+ actual = [1, 2, 3].to_compact_hash { |key| key + 1 unless key == 2 }
25
+ expected = {1 => 2, 3 => 4}
26
+ assert_equal(expected, actual, 'Compact hash incorrect')
27
+ end
28
+
29
+ def test_lazy_hash
30
+ hash = Jinx::LazyHash.new { |n| n * 2 }
31
+ assert_equal(2, hash[1], "Lazy hash value incorrect")
32
+ hash.merge!(2 => 3)
33
+ assert_equal({1 => 2, 2 => 3}, hash, "Lazy hash merge incorrect")
34
+ end
35
+
36
+ def test_array_operator_set_argument
37
+ array = [1, 2, 3]
38
+ set = [3, 4].to_set
39
+ assert_equal([3], array & set, "Array | Set result incorrect")
40
+ assert_equal([1, 2, 3, 4], array | set, "Array | Set result incorrect")
41
+ assert_equal([1, 2], array - set, "Array - Set result incorrect")
42
+ end
43
+
44
+ def test_empty_hash
45
+ assert_raises(NotImplementedError, "Assigment to empty hash succeeds") { Hash::EMPTY_HASH[:a] = 2 }
46
+ end
47
+
48
+ def test_set_first
49
+ assert_equal(1, [1, 2].to_set.first, "first of set incorrect")
50
+ assert_nil(Set.new.first, "first of empty set incorrect")
51
+ end
52
+
53
+ def test_assoc_values_single
54
+ expected = {:a => [1, 3], :b => [2, nil], :c => [nil, 4]}
55
+ actual = {:a => 1, :b => 2}.assoc_values({:a => 3, :c => 4})
56
+ assert_equal(expected, actual, "Association hash incorrect")
57
+ end
58
+
59
+ def test_assoc_values_multiple
60
+ expected = {:a => [1, 3, 4], :b => [2, nil, 5]}
61
+ actual = {:a => 1, :b => 2}.assoc_values({:a => 3}, { :a => 4, :b => 5 })
62
+ assert_equal(expected, actual, "Multiple association hash incorrect")
63
+ end
64
+
65
+ def test_detect_value
66
+ assert_equal(4, [1, 2, 3].detect_value { |item| item * 2 if item > 1 }, "Detect value incorrect")
67
+ assert_nil([1, 2, 3].detect_value { |item| item * 2 if item > 3 }, "Value incorrectly detected")
68
+ end
69
+
70
+ def test_detect_with_value
71
+ assert_equal([2, 1], [1, 2].detect_with_value { |item| item / 2 if item % 2 == 0 }, "Detect with value incorrect")
72
+ end
73
+
74
+ def test_array_filter
75
+ base = [1, 2, 3]
76
+ filter = base.filter { |n| n != 2 }
77
+ assert_equal([1, 3], filter.to_a, 'Filter incorrect')
78
+ base << 4
79
+ assert_equal([1, 3, 4], filter.to_a, 'Filter does not reflect operand modification')
80
+ filter << 5
81
+ assert_equal([1, 2, 3, 4, 5], base.to_a, 'Filter does not modify the base')
82
+ end
83
+
84
+ def test_enum_join
85
+ assert_equal("1", [1].filter { true }.join, "Enumerable singleton join incorrect")
86
+ assert_equal("1,2", [1, 2].filter { true }.join(','), "Enumerable join incorrect")
87
+ end
88
+
89
+ def test_array_filter_without_block
90
+ assert_equal([1, 3], [1, nil, 3, false].filter.to_a, 'Filter incorrect')
91
+ end
92
+
93
+ def test_set_filter_include
94
+ assert([1, 2, 3].to_set.filter { |n| n > 1 }.include?(2), 'Set filter include? incorrect')
95
+ assert(false == [1, 2, 3].to_set.filter { |n| n > 1 }.include?(1), 'Set filter include? incorrect')
96
+ end
97
+
98
+ def test_union
99
+ base = [1, 2]
100
+ sum = base.union([4])
101
+ assert_equal([1, 2, 4], sum.to_a, 'Enumerator union incorrect')
102
+ assert(sum.include?(2), "Enumerator union missing first array element")
103
+ assert(sum.include?(4), "Enumerator union missing second array element")
104
+ base << 3
105
+ assert_equal([1, 2, 3, 4], sum.to_a, 'Enumerator union does not reflect operand modification')
106
+ end
107
+
108
+ def test_intersection
109
+ base = [1, 2, 3, 4]
110
+ other = [3]
111
+ intersection = base.intersect(other)
112
+ assert_equal([3], intersection.to_a, 'Enumerator intersection incorrect')
113
+ other << 4 << 5
114
+ assert_equal([3, 4], intersection.to_a, 'Enumerator intersection does not reflect operand modification')
115
+ end
116
+
117
+ def test_difference
118
+ base = [1, 2, 3]
119
+ diff = base.difference([3])
120
+ assert_equal([1, 2], diff.to_a, 'Enumerator subtraction incorrect')
121
+ base << 4
122
+ assert_equal([1, 2, 4], diff.to_a, 'Enumerator subtraction does not reflect operand modification')
123
+ end
124
+
125
+ def test_wrap
126
+ assert_equal([2, 4, 6], [1, 2, 3].wrap { |n| n * 2 }.to_a, 'Wrap incorrect')
127
+ end
128
+
129
+ def test_enum_addition
130
+ a = [1, 2].filter { true }
131
+ b = [3, 4].filter { true }
132
+ ab = a + b
133
+ assert_equal([1, 2, 3, 4], ab.to_a, "Composite array incorrect")
134
+ a << 3
135
+ assert_equal([1, 2, 3, 3, 4], ab.to_a, "Addition does not reflect change to first enumerable")
136
+ b << 5
137
+ assert_equal([1, 2, 3, 3, 4, 5], ab.to_a, "Addition does not reflect change to second enumerable")
138
+ end
139
+
140
+ def test_partial_sort
141
+ sorted = [Array, Object, Numeric, Enumerable, Set].partial_sort
142
+ assert(sorted.index(Array) < sorted.index(Enumerable), "Partial sort order incorrect")
143
+ assert(sorted.index(Set) < sorted.index(Enumerable), "Partial sort order incorrect")
144
+ end
145
+
146
+ def test_hash_union
147
+ a = {:a => 1, :b => 2}
148
+ b = {:b => 3, :c => 4}
149
+ ab = a + b
150
+ assert_equal({:a => 1, :b => 2, :c => 4}, ab.keys.to_compact_hash { |k| ab[k] }, "Hash union incorrect")
151
+ assert_equal([1, 2, 4], ab.values.sort, "Hash union values incorrect")
152
+ a.delete(:b)
153
+ assert_equal({:a => 1, :b => 3, :c => 4}, ab.keys.to_compact_hash { |k| ab[k] }, "Hash union does not reflect underlying change")
154
+ end
155
+
156
+ def test_hash_compose
157
+ x = {:a => :c, :b => :d}
158
+ y = {:c => 1}
159
+ xy = x.compose(y)
160
+ assert_equal({:a => {:c => 1}}, xy.keys.to_compact_hash { |k| xy[k] }, "Composed hash incorrect")
161
+ y[:d] = 2
162
+ assert_equal({:a => {:c => 1}, :b => {:d => 2}}, xy.keys.to_compact_hash { |k| xy[k] }, "Composed hash does not reflect underlying change")
163
+ end
164
+
165
+ def test_hash_join
166
+ x = {:a => :c, :b => :d}
167
+ y = {:c => 1}
168
+ xy = x.join(y)
169
+ assert_equal({:a => 1}, xy.keys.to_compact_hash { |k| xy[k] }, "Joined hash incorrect")
170
+ y[:d] = 2
171
+ assert_equal({:a => 1, :b => 2}, xy.keys.to_compact_hash { |k| xy[k] }, "Joined hash does not reflect underlying change")
172
+ end
173
+
174
+ def test_hash_diff
175
+ x = {:a => 1, :b => 2, :c => 3}
176
+ y = {:b => 2, :c => 4, :d => 5}
177
+ assert_equal({:a => [1,nil], :c => [3,4], :d => [nil,5]}, x.diff(y), "Hash diff incorrect")
178
+ end
179
+
180
+ def test_to_assoc_hash
181
+ actual = [[:a, 1], [:b, 2, 3], [:c], []].to_assoc_hash
182
+ expected = {:a => 1, :b => [2,3], :c => nil}
183
+ assert_equal(expected, actual, 'Association hash incorrect')
184
+ end
185
+
186
+ def test_hashable_equal
187
+ assert_equal({:a => 1}, {:a => 1}.filter, "Hash equal incorrect")
188
+ end
189
+
190
+ def test_hash_enum_keys
191
+ hash = { 1 => :a, 2 => :b }
192
+ ek = hash.enum_keys
193
+ assert_equal([1, 2], ek.sort, "Hash key enumerator incorrect")
194
+ hash[3] = :c
195
+ assert_equal([1, 2, 3], ek.sort, "Hash key enumerator does not reflect hash change")
196
+ end
197
+
198
+ def test_hash_enum_keys_with_value
199
+ assert_equal([:b, :c], {:a => 1, :b => 2, :c => 2}.enum_keys_with_value(2).to_a, "Hash filtered value keys incorrect")
200
+ end
201
+
202
+ def test_hash_enum_keys_with_value_block
203
+ assert_equal([:b, :c], {:a => 1, :b => 2, :c => 3}.enum_keys_with_value { |v| v > 1 }.to_a, "Hash filtered value block keys incorrect")
204
+ end
205
+
206
+ def test_hash_enum_values
207
+ hash = { :a => 1, :b => 2 }
208
+ ev = hash.enum_values
209
+ assert_equal([1, 2], ev.sort, "Hash value enumerator incorrect")
210
+ hash[:c] = 3
211
+ assert_equal([1, 2, 3], ev.sort, "Hash value enumerator does not reflect hash change")
212
+ end
213
+
214
+ def test_hash_flatten
215
+ assert_equal([:a, :b, :c, :d, :e, :f, :g], {:a => {:b => :c}, :d => :e, :f => [:g]}.flatten, "Hash flatten incorrect")
216
+ end
217
+
218
+ def test_hash_first
219
+ assert_equal([:a, 1], {:a => 1, :b => 2}.first, "Hash first incorrect")
220
+ end
221
+
222
+ def test_hash_filter
223
+ assert_equal({:a => 1, :c => 3}, {:a => 1, :b => 2, :c => 3}.filter { |k, v| k != :b }, "Hash filter incorrect")
224
+ end
225
+
226
+ def test_hash_sort
227
+ assert_equal([['a', 1], ['b', 2]], {'a'=>1, 'b'=>2}.sort.to_a, "Hash sort incorrect")
228
+ end
229
+
230
+ def test_hash_sort_with_comparator
231
+ assert_equal([[:a, 1], [:b, 2]], {:a => 1, :b => 2}.sort { |k1, k2| k1.to_s <=> k2.to_s }, "Hash sort with comparator incorrect")
232
+ end
233
+
234
+ def test_hash_default_filter
235
+ assert_equal({:a => 1, :c => 3}, {:a => 1, :b => nil, :c => 3}.filter, "Hash default filter incorrect")
236
+ end
237
+
238
+ def test_hash_partition
239
+ assert_equal([{:a => 1, :c => 3}, {:b => 2}], {:a => 1, :b => 2, :c => 3}.split { |k, v| k == :a or v == 3 }, "Hash partition incorrect")
240
+ end
241
+
242
+ def test_hash_filter_on_key
243
+ filtered = {:a => 1, :b => 2, :c => 3}.filter_on_key { |k| k != :b }
244
+ assert_equal({:a => 1, :c => 3}, filtered.to_hash, "Hash on key filter incorrect")
245
+ assert_equal(1, filtered[:a], "Access on key filter inclusion incorrect")
246
+ assert_nil(filtered[:b], "Access on key filter exclusion incorrect")
247
+ end
248
+
249
+ def test_hash_filter_on_value
250
+ filtered = {:a => 1, :b => 2, :c => 3}.filter_on_value { |v| v != 2 }
251
+ assert_equal({:a => 1, :c => 3}, filtered.to_hash, "Hash on value filter incorrect")
252
+ end
253
+
254
+ def test_hash_compact
255
+ assert_equal({:a => 1, :c => 3}, {:a => 1, :b => nil, :c => 3}.compact.to_hash, "Compact hash incorrect")
256
+ end
257
+
258
+ def test_set_flatten
259
+ inner = Set.new << :a
260
+ actual = [inner, 'b'].flatten
261
+ expected = [:a, 'b']
262
+ assert_equal(expected, actual, 'Inner set not flattened')
263
+ end
264
+
265
+ def test_to_compact_hash
266
+ assert_equal({1 => 2, 2 => 3}, [1, 2].to_compact_hash { |item| item + 1 }, 'to_compact_hash result incorrect')
267
+ end
268
+
269
+ def test_to_compact_hash_with_index
270
+ assert_equal({:a => 1, :b => 2}, [:a, :b].to_compact_hash_with_index { |item, index| index + 1 }, 'to_compact_hash_with_index result incorrect')
271
+ end
272
+
273
+ def test_to_compact_hash_reject_missing
274
+ assert_equal({1 => 2, 2 => 3}, [1, 2, 3].to_compact_hash { |item| item + 1 unless item > 2 }, 'to_compact_hash maps a key with a nil value')
275
+ end
276
+
277
+ def test_series
278
+ actual = [1, 2, 3].to_series
279
+ assert_equal('1, 2 and 3', actual, 'Print string incorrect')
280
+ end
281
+
282
+ def test_empty_series
283
+ actual = [].to_series
284
+ assert_equal('', actual, 'Print string incorrect')
285
+ end
286
+
287
+ def test_singleton_series
288
+ actual = [1].to_series
289
+ assert_equal('1', actual, 'Print string incorrect')
290
+ end
291
+
292
+ def test_copy_recursive
293
+ hash = {1 => { 2 => 3 }, 4 => 5 }
294
+ copy = hash.copy_recursive
295
+ assert_equal(hash, copy, 'Copy not equal')
296
+ hash[1][2] = 6
297
+ assert_equal(3, copy[1][2], 'Copy reflects change to original')
298
+ hash[4] = 7
299
+ assert_equal(5, copy[4], 'Copy reflects change to original')
300
+ end
301
+
302
+ def test_case_insensitive_hash
303
+ hash = Jinx::CaseInsensitiveHash.new
304
+ hash[:UP] = :down
305
+ assert_equal(:down, hash['up'], "Case-insensitive hash look-up incorrect")
306
+ end
307
+
308
+ def test_key_transformer_hash
309
+ hash = Jinx::KeyTransformerHash.new { |k| k % 2 }
310
+ hash[1] = :a
311
+ assert_equal(:a, hash[1], 'Key transformer hash entered value not found')
312
+ assert_nil(hash[2], 'Transformed hash unentered value found')
313
+ assert_equal(:a, hash[3], 'Key transformer hash equivalent value not found')
314
+ end
315
+
316
+ def test_transformed_hash
317
+ hash = {:a => 1, :b => 2}
318
+ xfm = hash.transform_value { |v| v * 2 }
319
+ assert_equal(2, xfm[:a], 'Transformed hash accessor incorrect')
320
+ assert_equal([2, 4], xfm.values.sort, 'Transformed hash values incorrect')
321
+ assert(xfm.has_value?(4), 'Transformed hash value query incorrect')
322
+ assert(!xfm.has_value?(1), 'Transformed hash value query incorrect')
323
+ # base hash should be reflected in transformed hash
324
+ hash[:b] = 3; hash[:c] = 4
325
+ assert_equal(6, xfm[:b], 'Transformed hash does not reflect base hash change')
326
+ assert_equal(8, xfm[:c], 'Transformed hash does not reflect base hash change')
327
+ end
328
+
329
+ def test_hashinator
330
+ base = {:a => 1, :b => 2}.to_a
331
+ hash = Jinx::Hashinator.new(base)
332
+ assert_equal(base.to_set, hash.to_set, "Hashinator enumeration invalid")
333
+ assert_equal(1, hash[:a], "Hashinator a value invalid")
334
+ assert_equal(2, hash[:b], "Hashinator b value invalid")
335
+ assert_nil(hash[:c], "Hashinator has association not in the base")
336
+ base.first[1] = 3
337
+ assert_equal(3, hash[:a], "Hashinator does not reflect change to underlying Enumerator")
338
+ assert_equal(base, hash.to_hash.to_a, "Hashable to_hash incorrect")
339
+ end
340
+
341
+ def test_collector
342
+ assert_equal([2, [3, 4]], Jinx::Collector.on([1, [2, 3]]) { |n| n + 1 }, "Collector on nested array incorrect")
343
+ assert_nil(Jinx::Collector.on(nil) { |n| n + 1 }, "Collector on nil incorrect")
344
+ assert_equal(2, Jinx::Collector.on(1) { |n| n + 1 }, "Collector on non-collection incorrect")
345
+ end
346
+
347
+ def test_enumerate
348
+ counter = 0
349
+ nil.enumerate { |item| counter += item }
350
+ assert_equal(0, counter, "Enumerate on nil incorrect")
351
+ [1, 2, 3].enumerate { |item| counter += item }
352
+ assert_equal(6, counter, "Enumerate on array incorrect")
353
+ [1, [2, 3]].enumerate { |item| counter += 1 }
354
+ assert_equal(8, counter, "Enumerate on nested array incorrect")
355
+ 2.enumerate { |item| counter += item }
356
+ assert_equal(10, counter, "Enumerate on non-collection incorrect")
357
+ end
358
+
359
+ def test_to_enum
360
+ assert_equal([], nil.to_enum.to_a, "to_enum on nil incorrect")
361
+ assert_equal([1], 1.to_enum.to_a, "to_enum on non-collection incorrect")
362
+ array = [1, 2]
363
+ assert_same(array, array.to_enum, "to_enum on array incorrect")
364
+ s = 'a'
365
+ assert_same(s, s.to_enum, "to_enum on String incorrect")
366
+ end
367
+
368
+ def test_flattener
369
+ assert_equal([1, 2, 3], Jinx::Flattener.new([1, [2, 3]]).to_a, "Flattener on nested array incorrect")
370
+ assert_equal([], Jinx::Flattener.new(nil).to_a, "Flattener on nil incorrect")
371
+ assert_equal([1], Jinx::Flattener.new(1).to_a, "Flattener on non-collection incorrect")
372
+ assert(Jinx::Flattener.new(nil).all?, "Flattener all? on nil incorrect")
373
+ assert_equal([:b, :c, :e], {:a => {:b => :c}, :d => [:e]}.enum_values.flatten.to_a, "Enumerable flatten incorrect")
374
+ end
375
+
376
+ def test_hash_flattener
377
+ assert_equal([:a, :b, :c], {:a => {:b => :c}}.flatten.to_a, "Hash flatten incorrect")
378
+ assert_equal([:b, :c, :e], {:a => {:b => :c}, :d => [:e]}.enum_values.flatten.to_a, "Enumerable flatten incorrect")
379
+ end
380
+
381
+
382
+ def test_conditional_enumerator
383
+ assert_equal([1, 2], Jinx::ConditionalEnumerator.new([1, 2, 3]) { |i| i < 3 }.to_a, "ConditionalEnumerator filter not applied")
384
+ end
385
+
386
+ def test_enumerable_size
387
+ assert_equal(2, {:a => 1, :b => 2}.enum_keys.size, "Enumerable size incorrect")
388
+ end
389
+
390
+ def test_set_merge
391
+ set = [1, 2].to_set
392
+ merged = set.merge!([3])
393
+ assert_equal([1, 2, 3].to_set, merged, "Merged set incorrect")
394
+ assert_same(set, merged, "Set merge! did not return same set")
395
+ end
396
+
397
+ def test_set_add_all
398
+ actual = [1, 2].add_all([3])
399
+ expected = [1, 2, 3]
400
+ assert_equal(expected, actual, 'Set content not added')
401
+ end
402
+ end