javaclass 0.0.3 → 0.0.4

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 (175) hide show
  1. data/Rakefile +67 -56
  2. data/Readme.txt +42 -39
  3. data/example_task.rb +172 -0
  4. data/examples/check_interface_names.rb +44 -0
  5. data/examples/corpus.rb +19 -0
  6. data/examples/count_classes_in_modules.rb +38 -0
  7. data/examples/cumulative_dependencies.rb +39 -0
  8. data/examples/find_all_imported_types.rb +44 -0
  9. data/examples/find_referenced_modules.rb +53 -0
  10. data/examples/find_unreferenced_classes.rb +65 -0
  11. data/examples/generate_class_lists.rb +67 -43
  12. data/examples/profiler_scratchpad.rb +33 -0
  13. data/examples/simple_usage.rb +42 -0
  14. data/history.txt +29 -7
  15. data/javaclass.gemspec +31 -0
  16. data/lib/javaclass/adder_tree.rb +92 -0
  17. data/lib/javaclass/analyse/dependencies.rb +52 -0
  18. data/lib/javaclass/{metric/metrics.txt → analyse/ideas.txt} +2 -2
  19. data/lib/javaclass/analyse/transitive_dependencies.rb +52 -0
  20. data/lib/javaclass/classfile/access_flag_constants.rb +24 -0
  21. data/lib/javaclass/classfile/access_flags.rb +49 -26
  22. data/lib/javaclass/classfile/class_format_error.rb +37 -0
  23. data/lib/javaclass/classfile/class_magic.rb +16 -8
  24. data/lib/javaclass/classfile/class_version.rb +19 -25
  25. data/lib/javaclass/classfile/constant_pool.rb +110 -45
  26. data/lib/javaclass/classfile/constants/base.rb +33 -12
  27. data/lib/javaclass/classfile/constants/double_reference.rb +55 -41
  28. data/lib/javaclass/classfile/constants/single_reference.rb +29 -21
  29. data/lib/javaclass/classfile/constants/value.rb +43 -33
  30. data/lib/javaclass/classfile/java_class_header.rb +72 -46
  31. data/lib/javaclass/classfile/java_class_header_as_java_name.rb +33 -0
  32. data/lib/javaclass/classfile/java_class_header_shortcuts.rb +19 -0
  33. data/lib/javaclass/classfile/references.rb +21 -19
  34. data/lib/javaclass/classlist/class_entry.rb +26 -27
  35. data/lib/javaclass/classlist/jar_searcher.rb +34 -25
  36. data/lib/javaclass/classlist/list.rb +31 -31
  37. data/lib/javaclass/classlist/package_entry.rb +25 -24
  38. data/lib/javaclass/classpath/any_classpath.rb +48 -0
  39. data/lib/javaclass/classpath/class_not_found_error.rb +20 -0
  40. data/lib/javaclass/classpath/classpaths.txt +2 -2
  41. data/lib/javaclass/classpath/composite_classpath.rb +56 -54
  42. data/lib/javaclass/classpath/convention_classpath.rb +38 -0
  43. data/lib/javaclass/classpath/eclipse_classpath.rb +74 -0
  44. data/lib/javaclass/classpath/factory.rb +65 -0
  45. data/lib/javaclass/classpath/file_classpath.rb +47 -0
  46. data/lib/javaclass/classpath/folder_classpath.rb +42 -44
  47. data/lib/javaclass/classpath/jar_classpath.rb +91 -52
  48. data/lib/javaclass/classpath/java_home_classpath.rb +24 -13
  49. data/lib/javaclass/classpath/maven_classpath.rb +44 -0
  50. data/lib/javaclass/classpath/temporary_unpacker.rb +111 -0
  51. data/lib/javaclass/classpath/tracking_classpath.rb +144 -0
  52. data/lib/javaclass/classscanner/ideas.txt +3 -0
  53. data/lib/javaclass/classscanner/imported_types.rb +29 -0
  54. data/lib/javaclass/classscanner/scanners.rb +29 -0
  55. data/lib/javaclass/delegate_directive.rb +15 -0
  56. data/lib/javaclass/dsl/caching_classpath.rb +38 -0
  57. data/lib/javaclass/dsl/classpath_analysers.rb +27 -0
  58. data/lib/javaclass/dsl/java_name_factory.rb +79 -0
  59. data/lib/javaclass/dsl/loader.rb +42 -0
  60. data/lib/javaclass/dsl/loading_classpath.rb +53 -0
  61. data/lib/javaclass/dsl/mixin.rb +54 -0
  62. data/lib/javaclass/gems/zip_file.rb +154 -0
  63. data/lib/javaclass/java_language.rb +50 -0
  64. data/lib/javaclass/java_name.rb +329 -55
  65. data/lib/javaclass/java_name_scanner.rb +95 -0
  66. data/lib/javaclass/resources/iso_3166_countries.txt +240 -0
  67. data/lib/javaclass/resources/jdk0_packages.txt +6 -0
  68. data/lib/javaclass/resources/jdk1_packages.txt +6 -0
  69. data/lib/javaclass/resources/jdk2_packages.txt +4 -0
  70. data/lib/javaclass/resources/jdk3_packages.txt +6 -0
  71. data/lib/javaclass/resources/jdk4_packages.txt +22 -0
  72. data/lib/javaclass/resources/jdk5_packages.txt +5 -0
  73. data/lib/javaclass/resources/jdk6_packages.txt +7 -0
  74. data/lib/javaclass/resources/jdk7_packages.txt +0 -0
  75. data/lib/javaclass/resources/jdk_packages.txt +53 -0
  76. data/lib/javaclass/resources/reserved_words.txt +50 -0
  77. data/lib/javaclass/string_hexdump.rb +76 -0
  78. data/lib/javaclass/string_ux.rb +21 -10
  79. data/lib/javaclass.rb +16 -41
  80. data/license.txt +28 -0
  81. data/planned.txt +13 -0
  82. data/test/data/Object_102.class +0 -0
  83. data/test/data/Runnable_102.class +0 -0
  84. data/test/data/access_flags/AccessFlagsTestAnnotation.class +0 -0
  85. data/test/data/access_flags/AccessFlagsTestAnnotation.java +3 -0
  86. data/test/data/access_flags/AccessFlagsTestEnum$1.class +0 -0
  87. data/test/data/access_flags/AccessFlagsTestEnum.class +0 -0
  88. data/test/data/access_flags/AccessFlagsTestEnum.java +6 -0
  89. data/test/data/access_flags/AccessFlagsTestInner$1.class +0 -0
  90. data/test/data/access_flags/AccessFlagsTestInner$2.class +0 -0
  91. data/test/data/access_flags/AccessFlagsTestInner.class +0 -0
  92. data/test/data/access_flags/AccessFlagsTestInner.java +13 -0
  93. data/test/data/access_flags/AccessFlagsTestPackage.class +0 -0
  94. data/test/data/access_flags/AccessFlagsTestPackage.java +1 -1
  95. data/test/data/api/packagename/AccessFlagsTestPublic.class +0 -0
  96. data/test/data/class_version/ClassVersionTest17.class +0 -0
  97. data/test/data/class_version/make.bat +6 -2
  98. data/test/data/eclipse_classpath/classes/ClassVersionTest12.class +0 -0
  99. data/test/data/eclipse_classpath/lib/JarClasspathTest.jar +0 -0
  100. data/test/data/eclipse_classpath/test-classes/ClassVersionTest13.class +0 -0
  101. data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/ClassVersionTest10.class +0 -0
  102. data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/package/ClassVersionTest11.class +0 -0
  103. data/test/data/jar_classpath/JarClasspathTest.jar +0 -0
  104. data/test/data/jar_classpath/JarClasspathTest.zip +0 -0
  105. data/test/data/jar_classpath/JarClasspathTestManifest.jar +0 -0
  106. data/test/data/jar_classpath/JarClasspathTestMultiManifest.jar +0 -0
  107. data/test/data/jar_classpath/make.bat +6 -2
  108. data/test/data/jar_searcher/BrokenRunnable_102.class +0 -0
  109. data/test/data/java_home_classpath/jdk118/lib/classes.zip +0 -0
  110. data/test/data/java_name_scanner/META-INF/MANIFEST.MF +12 -0
  111. data/test/data/java_name_scanner/plugin.xml +18 -0
  112. data/test/data/maven_classpath/module/pom.xml +8 -0
  113. data/test/data/maven_classpath/module/target/classes/ClassVersionTest12.class +0 -0
  114. data/test/data/maven_classpath/pom.xml +8 -0
  115. data/test/data/maven_classpath/target/classes/ClassVersionTest10.class +0 -0
  116. data/test/data/maven_classpath/target/test-classes/ClassVersionTest11.class +0 -0
  117. data/test/data/transitive_dependencies/A.class +0 -0
  118. data/test/data/transitive_dependencies/A.java +5 -0
  119. data/test/data/transitive_dependencies/B.class +0 -0
  120. data/test/data/transitive_dependencies/B.java +3 -0
  121. data/test/data/transitive_dependencies/C.class +0 -0
  122. data/test/data/transitive_dependencies/C.java +3 -0
  123. data/test/data/transitive_dependencies/Start.class +0 -0
  124. data/test/data/transitive_dependencies/Start.java +4 -0
  125. data/test/data/transitive_dependencies/make.bat +3 -0
  126. data/test/data/zip_file/commons-math-2.2-broken.zip +0 -0
  127. data/test/data/zip_file/regenerated-with-7zip.zip +0 -0
  128. data/test/data/zip_file/regenerated-with-jar.zip +0 -0
  129. data/test/dot_classpath.rb +33 -0
  130. data/test/logging_folder_classpath.rb +19 -0
  131. data/test/setup.rb +1 -1
  132. data/test/test_access_flags.rb +58 -32
  133. data/test/test_adder_tree.rb +78 -0
  134. data/test/test_any_classpath.rb +39 -0
  135. data/test/test_base.rb +9 -7
  136. data/test/test_caching_classpath.rb +41 -0
  137. data/test/test_class_entry.rb +60 -60
  138. data/test/test_class_magic.rb +31 -0
  139. data/test/test_class_version.rb +25 -25
  140. data/test/test_composite_classpath.rb +22 -23
  141. data/test/test_constant_pool.rb +37 -13
  142. data/test/test_convention_classpath.rb +39 -0
  143. data/test/test_eclipse_classpath.rb +73 -0
  144. data/test/test_factory.rb +61 -0
  145. data/test/test_folder_classpath.rb +26 -10
  146. data/test/test_imported_types.rb +34 -0
  147. data/test/test_jar_classpath.rb +29 -14
  148. data/test/test_jar_searcher.rb +27 -14
  149. data/test/test_java_class_header.rb +22 -10
  150. data/test/test_java_class_header_as_java_name.rb +41 -0
  151. data/test/test_java_home_classpath.rb +17 -11
  152. data/test/test_java_name.rb +204 -64
  153. data/test/test_java_name_factory.rb +52 -0
  154. data/test/test_java_name_scanner.rb +24 -0
  155. data/test/test_javaclass_api.rb +43 -0
  156. data/test/test_list.rb +58 -44
  157. data/test/test_load_directive.rb +34 -0
  158. data/test/test_maven_classpath.rb +46 -0
  159. data/test/test_package_entry.rb +27 -22
  160. data/test/test_references.rb +14 -14
  161. data/test/test_string_hexdump.rb +24 -0
  162. data/test/test_string_ux.rb +18 -106
  163. data/test/test_tracking_classpath.rb +112 -0
  164. data/test/test_transitive_dependencies.rb +31 -0
  165. data/test/test_unpacking_jar_classpath.rb +43 -0
  166. data/test/test_zip_file.rb +33 -0
  167. data/test/ts_all_tests.rb +80 -18
  168. data/thanks.txt +2 -0
  169. metadata +151 -22
  170. data/lib/javaclass/classpath/port_ClassPathEntry.java +0 -202
  171. data/lib/javaclass/classpath/port_ClassPathEntryFactory.java +0 -311
  172. data/lib/javaclass/classpath/port_DirectoryRepository.java +0 -24
  173. data/lib/javaclass/metric/ccd.rb +0 -68
  174. data/lib/javaclass/metric/class_usage.rb +0 -41
  175. data/test/test_javaclass.rb +0 -22
@@ -1,98 +1,100 @@
1
1
  require 'javaclass/classpath/jar_classpath'
2
2
  require 'javaclass/classpath/folder_classpath'
3
+ require 'javaclass/classpath/file_classpath'
3
4
 
4
5
  module JavaClass
5
- module Classpath
6
- # List of class path elements.
6
+
7
+ # The module Classpath is for separating namespaces. It contains the abstraction of classpath to load binary class file data from.
8
+ # It does not contain references to ClassFile::JavaClassHeader nor does it parse the classes. It just provides the binary data
9
+ # (*.class files). A classpath is a composite containing classpath elements, e.g. libraries (JARs), folders, modules. It is low-level.
10
+ # For an example see {how to count the number of classes in each module}[link:/files/lib/generated/examples/count_classes_in_modules_txt.html].
11
+ # Author:: Peter Kofler
12
+ module Classpath
13
+
14
+ # List of class path elements constructed from a full _CLASSPATH_ variable.
7
15
  # Author:: Peter Kofler
8
- class CompositeClasspath
9
- # Return the list of classnames found in this path.
10
- def initialize
16
+ class CompositeClasspath < FileClasspath
17
+
18
+ # Create an empty classpath composite root. The optional _file_ is for
19
+ # identifying subclasses.
20
+ def initialize(root='.')
21
+ super(root)
11
22
  @elements = []
12
23
  end
13
24
 
14
- # Return the classpath elements of this path.
25
+ # Return all the classpath elements (the children) of this path and all child paths.
15
26
  def elements
16
- @elements.dup
27
+ # [self] + */
28
+ @elements.map { |cp| cp.elements }.flatten
17
29
  end
18
30
 
19
- # Search the given _path_ recursievely for zips or jars. Add all found jars to this classpath.
20
- def find_jars(path)
21
- current = Dir.getwd
22
- begin
23
- Dir.chdir File.expand_path(path)
24
-
25
- Dir['*'].collect do |name|
26
- if FileTest.directory?(name)
27
- find_jars(name)
28
- elsif name =~ /\.jar$|\.zip$/
29
- add_file_name File.expand_path(name)
30
- end
31
- end
32
-
33
- ensure
34
- Dir.chdir current
35
- end
36
- end
37
-
38
- # Add the _name_ class path file/folder name to the list.
31
+ # Add the _name_ class path which may be a file or a folder to this classpath.
39
32
  def add_file_name(name)
40
- if FileTest.directory? name
33
+ if FolderClasspath.valid_location?(name)
41
34
  add_element(FolderClasspath.new(name))
42
- else
35
+ elsif JarClasspath.valid_location?(name)
43
36
  add_element(JarClasspath.new(name))
37
+ else
38
+ warn("tried to add an invalid classpath location #{name}")
44
39
  end
45
40
  end
46
41
 
47
42
  # Add the _elem_ classpath element to the list.
48
43
  def add_element(elem)
49
- @elements << elem unless @elements.find { |cpe| cpe == elem }
44
+ if elem.count > 0 && !@elements.find { |cpe| cpe == elem }
45
+ @elements << elem
46
+ end
50
47
  elem.additional_classpath.each do |acpe|
51
48
  # referred classpath elements may be missing
52
- if FileTest.exist? acpe
53
- add_element(JarClasspath.new(acpe))
54
- end
49
+ if JarClasspath.valid_location?(acpe)
50
+ add_element(JarClasspath.new(acpe))
51
+ end
55
52
  end
56
53
  end
57
54
 
58
- # Return false.
59
- def jar?
60
- false
61
- end
62
-
63
- # Return an empty array.
64
- def additional_classpath
65
- []
66
- end
67
-
68
- # Return the list of class names found in this classpath.
69
- def names
70
- @elements.collect { |e| e.names }.flatten.uniq
55
+ # Return the list of class names found in this classpath. An additional block is used as _filter_ on class names.
56
+ def names(&filter)
57
+ @elements.collect { |e| e.names(&filter) }.flatten.uniq
71
58
  end
72
59
 
73
- # Return if _classname_ is included in this classpath.
60
+ # Return if _classname_ is included in this classpath. If yes, return the count (usually 1).
74
61
  def includes?(classname)
75
- @elements.find { |e| e.includes?(classname) } != nil
62
+ key = to_key(classname)
63
+ found = find_element_for(key)
64
+ if found then 1 else nil end
76
65
  end
77
66
 
78
67
  # Load the binary data of the file name or class name _classname_ from this classpath.
79
68
  def load_binary(classname)
80
- found = @elements.find { |e| e.includes?(classname) }
81
- if (found)
82
- return found.load_binary(classname)
69
+ key = to_key(classname)
70
+ found = find_element_for(key)
71
+ unless found
72
+ raise ClassNotFoundError.new(key, to_s)
83
73
  end
84
- raise "class #{classname} not found in classpath #{to_s}"
74
+ found.load_binary(key)
85
75
  end
86
76
 
87
- # Return the number of classes in this jar.
77
+ # Return the number of classes in this classpath.
88
78
  def count
89
79
  @elements.inject(0) { |s,e| s + e.count }
90
80
  end
91
81
 
92
82
  def to_s
93
- @elements.collect { |e| e.to_s }.join(',')
83
+ str = super.to_s
84
+ if str=='.'
85
+ @elements.collect { |e| e.to_s }.join(',')
86
+ else
87
+ str
88
+ end
94
89
  end
95
90
 
91
+ private
92
+
93
+ # Return the matching classpath element for the given _key_
94
+ def find_element_for(key)
95
+ @elements.find { |e| e.includes?(key) }
96
+ end
97
+
96
98
  end
97
99
 
98
100
  end
@@ -0,0 +1,38 @@
1
+ require 'javaclass/classpath/folder_classpath'
2
+ require 'javaclass/classpath/jar_classpath'
3
+
4
+ module JavaClass
5
+ module Classpath
6
+
7
+ # A Java project by naming convention, contains a classes and a lib folder.
8
+ # Author:: Peter Kofler
9
+ class ConventionClasspath < FolderClasspath
10
+
11
+ CLASSES = 'classes'
12
+
13
+ # Check if the _file_ is a valid location.
14
+ def self.valid_location?(file)
15
+ FolderClasspath.valid_location?(file) &&
16
+ FolderClasspath.valid_location?(File.join(file, CLASSES))
17
+ end
18
+
19
+ # Create a classpath for _folder_ / classes.
20
+ def initialize(folder)
21
+ super(File.join(folder, CLASSES))
22
+ @root = folder
23
+ end
24
+
25
+ # Return list of additional classpath elements defined in the lib folder.
26
+ def additional_classpath
27
+ lib = File.join(@root, 'lib')
28
+ if FolderClasspath.valid_location?(lib)
29
+ Dir.entries(lib).map { |e| File.join(lib, e) }.find_all { |e| JarClasspath.valid_location?(e) }
30
+ else
31
+ []
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,74 @@
1
+ require 'javaclass/classpath/composite_classpath'
2
+
3
+ module JavaClass
4
+ module Classpath
5
+
6
+ # An Eclipse workspace aware classpath.
7
+ # Author:: Peter Kofler
8
+ class EclipseClasspath < CompositeClasspath
9
+
10
+ DOT_CLASSPATH = '.classpath'
11
+
12
+ # Check if the _file_ is a valid location for an Eclipse classpath.
13
+ def self.valid_location?(file)
14
+ FileTest.exist?(file) && FileTest.directory?(file) && FileTest.exist?(File.join(file, DOT_CLASSPATH))
15
+ end
16
+
17
+ # Add an Eclipse variable _name_ with _value to look up libraries.
18
+ def self.add_variable(name, value)
19
+ @@variables ||= Hash.new
20
+ @@variables.delete(name)
21
+ @@variables[name] = value if value
22
+ end
23
+
24
+ # Skip the lib containers if .classpath.
25
+ def self.skip_lib(flag=:skip)
26
+ @@skip_lib = flag
27
+ end
28
+
29
+ # Create a classpath for an Eclipse base project in _folder_ where the .classpath is.
30
+ def initialize(folder)
31
+ unless EclipseClasspath::valid_location?(folder)
32
+ raise IOError, "folder #{folder} not an Eclipse project"
33
+ end
34
+ dot_classpath = File.join(folder, DOT_CLASSPATH)
35
+ super(dot_classpath)
36
+ classpath = IO.readlines(dot_classpath)
37
+
38
+ classpath.find_all { |line| line =~ /kind\s*=\s*"output"/ }.each do |line|
39
+ if line =~ /path\s*=\s*"([^"]+)"/
40
+ add_file_name(File.join(folder, $1))
41
+ end
42
+ end
43
+
44
+ classpath.find_all { |line| line =~ /output\s*=\s*"/ }.each do |line|
45
+ if line =~ /output\s*=\s*"([^"]+)"/
46
+ add_file_name(File.join(folder, $1))
47
+ end
48
+ end
49
+
50
+ @@skip_lib ||= false
51
+ unless @@skip_lib
52
+
53
+ classpath.find_all { |line| line =~ /kind\s*=\s*"lib"/ }.each do |line|
54
+ if line =~ /path\s*=\s*"([^"]+)"/
55
+ add_file_name(File.join(folder, $1))
56
+ end
57
+ end
58
+
59
+ @@variables ||= Hash.new
60
+ classpath.find_all { |line| line =~ /kind\s*=\s*"var"/ }.each do |line|
61
+ if line =~ /path\s*=\s*"([^\/]+)\/([^"]+)"/
62
+ path = @@variables[$1]
63
+ add_file_name(File.join(path, $2)) if path
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,65 @@
1
+ require 'javaclass/classpath/java_home_classpath'
2
+ require 'javaclass/classpath/composite_classpath'
3
+ require 'javaclass/classpath/maven_classpath'
4
+ require 'javaclass/classpath/eclipse_classpath'
5
+ require 'javaclass/classpath/convention_classpath'
6
+
7
+ module JavaClass
8
+ module Classpath
9
+
10
+ # Factory methods to create different kind of classpaths.
11
+ # Author:: Peter Kofler
12
+ module Factory
13
+
14
+ # Parse the given path variable _path_ and return a chain of class path elements.
15
+ # The path variable is separated by : or ; depending on the platform.
16
+ # Adds the classpath to the optional _cp_ element else creates a CompositeClasspath.
17
+ def classpath(path, cp=CompositeClasspath.new)
18
+ path.split(File::PATH_SEPARATOR).each { |cpe| cp.add_file_name(cpe) }
19
+ cp
20
+ end
21
+
22
+ # Parse and set the system classpath. Needs +JAVA_HOME+ to be set. Uses additional environment
23
+ # +CLASSPATH+ if set. Adds the classpath to the optional _cp_ element else creates a CompositeClasspath.
24
+ def environment_classpath(cp=CompositeClasspath.new)
25
+ full_classpath(ENV['JAVA_HOME'], ENV['CLASSPATH'], cp)
26
+ end
27
+
28
+ # Parse the given path variable _path_ and return a chain of class path elements together with _javahome_ if any.
29
+ def full_classpath(javahome, path=nil, cp=CompositeClasspath.new)
30
+ cp.add_element(JavaHomeClasspath.new(javahome)) if javahome
31
+ cp = classpath(path, cp) if path
32
+ cp
33
+ end
34
+
35
+ Classpath_types = [EclipseClasspath, MavenClasspath, ConventionClasspath]
36
+
37
+ # Create a classpath from a workspace _basepath_ which contains Eclipse or Maven projects.
38
+ def workspace(basepath, cp=CompositeClasspath.new)
39
+ # check for a valid project in this folder
40
+ Classpath_types.each do |classpath_type|
41
+ if classpath_type.valid_location?(basepath)
42
+ cp.add_element(classpath_type.new(basepath))
43
+ return cp
44
+ end
45
+ end
46
+
47
+ # check the children as regular workspace
48
+ Dir.entries(basepath).each do |entry|
49
+ next if entry == '.' || entry == '..'
50
+ file = File.join(basepath, entry)
51
+
52
+ Classpath_types.each do |classpath_type|
53
+ if classpath_type.valid_location?(file)
54
+ cp.add_element(classpath_type.new(file))
55
+ break
56
+ end
57
+ end
58
+ end if FileTest.directory? basepath
59
+ cp
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,47 @@
1
+ require 'javaclass/classpath/class_not_found_error'
2
+
3
+ module JavaClass
4
+ module Classpath
5
+
6
+ # Abstract concept of a classpath pointing to a file.
7
+ # Author:: Peter Kofler
8
+ class FileClasspath
9
+
10
+ # Create a classpath with this _root_ .
11
+ def initialize(root)
12
+ @root = root
13
+ end
14
+
15
+ # Return +false+ as this is no jar.
16
+ def jar?
17
+ false
18
+ end
19
+
20
+ # Return an empty array.
21
+ def additional_classpath
22
+ []
23
+ end
24
+
25
+ def to_s
26
+ @root.to_s
27
+ end
28
+
29
+ # Equality with _other_ delegated to to_s.
30
+ def ==(other)
31
+ other.class == self.class && other.to_s == self.to_s
32
+ end
33
+
34
+ # Return the classpath elements of this (composite) classpath
35
+ def elements
36
+ [self]
37
+ end
38
+
39
+ # Return the key for the access of this class file named _classname_ .
40
+ def to_key(classname)
41
+ classname.to_javaname.to_class_file
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -1,55 +1,55 @@
1
+ require 'javaclass/classpath/file_classpath'
2
+ require 'javaclass/java_language'
1
3
  require 'javaclass/java_name'
2
4
 
3
5
  module JavaClass
4
- module Classpath # :nodoc:
5
- # Abstraction of a folder on the CLASSPATH.
6
+ module Classpath
7
+
8
+ # Abstraction of a folder on the CLASSPATH. This is a leaf in the classpath tree.
6
9
  # Author:: Peter Kofler
7
- class FolderClasspath
8
- # Return the list of classnames found in this _folder_ .
9
- def initialize(folder)
10
- @folder = folder
11
- raise IOError, "folder #{@folder} not found" if !FileTest.exist? @folder
12
- raise "#{@folder} is no folder" if !FileTest.directory? @folder
13
- @classes = list_classes.collect { |cl| cl.to_javaname }
14
- end
10
+ class FolderClasspath < FileClasspath
15
11
 
16
- # Return false.
17
- def jar?
18
- false
12
+ # Check if the _file_ is a valid location for a folder classpath.
13
+ def self.valid_location?(file)
14
+ FileTest.exist?(file) && FileTest.directory?(file)
19
15
  end
20
-
21
- # Return an empty array.
22
- def additional_classpath
23
- []
16
+
17
+ # Create a classpath with this _folder_ .
18
+ def initialize(folder)
19
+ super(folder)
20
+ unless FolderClasspath::valid_location?(folder)
21
+ raise IOError, "folder #{folder} not found/no folder"
22
+ end
23
+ @folder = folder
24
+ init_classes
24
25
  end
25
-
26
- # Return the list of class names found in this folder.
27
- def names
28
- @classes.dup
26
+
27
+ # Return the list of class names found in this folder. An additional block is used as _filter_ on class names.
28
+ def names(&filter)
29
+ if block_given?
30
+ @class_names.find_all { |n| filter.call(n) }
31
+ else
32
+ @class_names.dup
33
+ end
29
34
  end
30
35
 
31
36
  # Return if _classname_ is included in this folder.
32
37
  def includes?(classname)
33
- @classes.include?(normalize(classname))
38
+ @class_lookup[to_key(classname).file_name]
34
39
  end
35
40
 
36
- # Load the binary data of the file name or class name _classname_ from this jar.
41
+ # Load the binary data of the file name or class name _classname_ from this folder.
37
42
  def load_binary(classname)
38
- raise "class #{classname} not found in #{@folder}" unless includes?(classname)
39
- File.open(File.join(@folder, normalize(classname)), 'rb') {|io| io.read }
43
+ key = to_key(classname)
44
+ unless includes?(key)
45
+ raise ClassNotFoundError.new(key, @folder)
46
+ end
47
+ File.open(File.join(@folder, key), 'rb') { |io| io.read.freeze }
40
48
  end
41
49
 
42
50
  # Return the number of classes in this folder.
43
51
  def count
44
- @classes.size
45
- end
46
-
47
- def to_s
48
- @folder
49
- end
50
-
51
- def ==(other)
52
- other.class == FolderClasspath && other.to_s == self.to_s
52
+ @class_names.size
53
53
  end
54
54
 
55
55
  private
@@ -60,23 +60,21 @@ module JavaClass
60
60
  begin
61
61
  Dir.chdir @folder
62
62
 
63
- list = Dir['**/*.class']
63
+ list = Dir["**/*#{JavaLanguage::CLASS}"]
64
64
 
65
65
  ensure
66
66
  Dir.chdir current
67
67
  end
68
- list.sort
68
+ list
69
69
  end
70
70
 
71
- # Normalize the file name or class name _classname_ to be a file name in the jar.
72
- def normalize(classname)
73
- if classname !~ /\.class$/
74
- classname.gsub(/\./,'/') + '.class'
75
- else
76
- classname
77
- end
71
+ # Set up the class names.
72
+ def init_classes
73
+ @class_names = list_classes.sort.reject { |n| n =~ /package-info\.class$/ }.collect { |cl| JavaClassFileName.new(cl) }
74
+ pairs = @class_names.map { |name| [name.file_name, 1] }.flatten
75
+ @class_lookup = Hash[ *pairs ] # file_name (String) => anything
78
76
  end
79
-
77
+
80
78
  end
81
79
 
82
80
  end