jinx 2.1.1

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