javaclass 0.0.3 → 0.0.4

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