java_head 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +2 -0
- data/lib/java_head/class.rb +133 -0
- data/lib/java_head/classpath.rb +14 -0
- data/lib/java_head/exceptions.rb +23 -0
- data/lib/java_head/package.rb +166 -0
- data/lib/java_head/version.rb +1 -1
- data/lib/java_head/version.rb~ +3 -0
- data/lib/java_head.rb +17 -313
- data/test/test_class.rb +6 -5
- data/test/test_package.rb +5 -4
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4deb19e80661594ddfdb486360e65d7039e5c2d3
|
4
|
+
data.tar.gz: dbfe74da39a53692b47c0e5cd9e789a1d66a9ef9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3186e9b7b159c08b60af278663e514d93e5e34136143abeccc4e47ffaaab4cf47202e072863f5dbbf7771a6d07ab801113c4b269fe952ad652b42c43e459cfe5
|
7
|
+
data.tar.gz: 31936daf7918ed3a838ff1eafe2d60d620488a4008b002d1e87071ca4cb588c9fe8d71cfc317dd40b47f62c22ea06ccbb705001d98981fdec8b59afce8802fa1
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -45,6 +45,8 @@ jclass.remove_class # Remove the .class file
|
|
45
45
|
jclass.run # Do the same thing with only one method, this returns the same as #exec()
|
46
46
|
jclass.run('Hello','World') # You can also pass command-line arguments to your Java programs
|
47
47
|
|
48
|
+
# NOTE: This library requires that you install the java command line tools (java and javac) in order to function. If you do not, it will fail in mysterious ways due to an inability to compile or run Java
|
49
|
+
|
48
50
|
|
49
51
|
|
50
52
|
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module JavaHead
|
2
|
+
|
3
|
+
# Class to represent Java Classes
|
4
|
+
class Class
|
5
|
+
# Construct a new Class object
|
6
|
+
#
|
7
|
+
# @param [String] name the full name of the class
|
8
|
+
def initialize(name)
|
9
|
+
raise ClassException, "Invalid class name #{name}" unless name.match FORMAT
|
10
|
+
|
11
|
+
names = name.split('.')
|
12
|
+
@name = names.pop.freeze
|
13
|
+
@package = JavaHead::Package.get(names.join('.'))
|
14
|
+
@path = @package.path.join("#{@name}.java")
|
15
|
+
|
16
|
+
raise ClassException, "Location not found for class #{name}" unless @path.exist? and @path.file?
|
17
|
+
end
|
18
|
+
# name, package, and path are publicly visible
|
19
|
+
attr_reader :name, :package, :path
|
20
|
+
|
21
|
+
# Get the fully qualified name of the class
|
22
|
+
# @return [String] the full name of the class, e.g. com.example.projects.Circle
|
23
|
+
def fullname
|
24
|
+
"#{@package.fullname}.#{@name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# #to_s is #fullname
|
28
|
+
alias to_s fullname
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
# Compile the program
|
34
|
+
# Raises a CompilerException if there was a problem compiling
|
35
|
+
# @return [JavaHead::Class] this class object
|
36
|
+
def compile(*args)
|
37
|
+
remove_class if compiled?
|
38
|
+
command = 'javac '
|
39
|
+
args.each do |arg|
|
40
|
+
arg = arg.to_s
|
41
|
+
raise CompilerException, "Invalid compiling argument #{arg}" unless arg.match ARGFORMAT
|
42
|
+
end
|
43
|
+
command << args.join(' ')
|
44
|
+
command << ' '
|
45
|
+
command << @path.to_s
|
46
|
+
output = `#{command}`
|
47
|
+
raise CompilerException, "Class #{fullname} could not compile" unless compiled?
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
# Remove the existing compiled class
|
52
|
+
#
|
53
|
+
# @return [JavaHead::Class, Boolean] this class object or false if not successful
|
54
|
+
def remove_class
|
55
|
+
Dir.chdir(@package.path) do
|
56
|
+
Pathname.glob("#{@name}$*.class") do |pathname|
|
57
|
+
pathname.unlink
|
58
|
+
end
|
59
|
+
Pathname.new("#{@name}.class").unlink
|
60
|
+
end
|
61
|
+
self
|
62
|
+
|
63
|
+
# the file doesn't exist or there was a problem loading it
|
64
|
+
rescue Errno::ENOENT
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
|
68
|
+
# Test to see if compilation works, args are passed to the compile method
|
69
|
+
#
|
70
|
+
# @param [Array] args the arguments to be passed to the #compile method
|
71
|
+
# @return [JavaHead::Class,NilClass] this class object or nil if the compilation failed
|
72
|
+
def test(*args)
|
73
|
+
compile(*args)
|
74
|
+
remove_class
|
75
|
+
self
|
76
|
+
rescue Exception => e
|
77
|
+
puts "Exception of type #{e.class} while compiling #{fullname}: #{e}"
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
# Integrated compile, run, remove_class
|
82
|
+
# This method assumes to some extent that
|
83
|
+
# compilation will succeed, so although this may fail,
|
84
|
+
# its arguments are passed to the exec method
|
85
|
+
#
|
86
|
+
# @param [Array] args the arguments to be passed to the #exec method
|
87
|
+
# @return [String] the output created by the Java program
|
88
|
+
def run(*args)
|
89
|
+
compile # this is a simple list of things for the interpreter to do
|
90
|
+
output = exec *args
|
91
|
+
remove_class
|
92
|
+
output # return output
|
93
|
+
end
|
94
|
+
|
95
|
+
# Check if the class is compiled?
|
96
|
+
#
|
97
|
+
# @return [Boolean] whether or not the class compiled
|
98
|
+
def compiled?
|
99
|
+
@path.dirname.join("#{@name}.class").exist?
|
100
|
+
end
|
101
|
+
|
102
|
+
# Take given command line arguments, check them for validity, add them to a java command and run the command to execute the class
|
103
|
+
#
|
104
|
+
# @param [Array] args the command-line arguments to be passed to the Java program
|
105
|
+
# @return [String] the output of the program execution
|
106
|
+
def exec(*args)
|
107
|
+
raise RunnerException, "Class #{fullname} cannot be run because it is not compiled" unless compiled?
|
108
|
+
command = "java #{fullname}"
|
109
|
+
args.each do |arg|
|
110
|
+
arg = arg.to_s
|
111
|
+
raise RunnerException, "Invalid command-line argument: #{arg}" unless arg.match ARGFORMAT
|
112
|
+
command << ' '
|
113
|
+
command << arg
|
114
|
+
end
|
115
|
+
`#{command}`
|
116
|
+
end
|
117
|
+
|
118
|
+
# Inspect incorporates meaningful data like name, location and whether class is compiled
|
119
|
+
# @return [String] useful data about the current object
|
120
|
+
def inspect
|
121
|
+
"[Java Class, name: #{fullname}, path: #{@path}, #{ compiled? ? 'Compiled' : 'Not Compiled'}]"
|
122
|
+
end
|
123
|
+
|
124
|
+
# The format for command-line arguments
|
125
|
+
ARGFORMAT = /^[\-a-zA-Z@][a-zA-Z0-9\-:="'@]*$/.freeze
|
126
|
+
# The format for classnames, e.g. com.example.projects.Shape
|
127
|
+
FORMAT = /^([a-z_][a-z0-9_]*\.)*[A-Z][a-z0-9_]*$/.freeze
|
128
|
+
|
129
|
+
# include all JavaHead Exceptions
|
130
|
+
include JavaHead::Exceptions
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module JavaHead
|
2
|
+
# An array of Pathnames representing the CLASSPATH environment variable
|
3
|
+
# Defaults to the current values of the $CLASSPATH environment variable
|
4
|
+
CLASSPATH = [Pathname.new('.')]
|
5
|
+
|
6
|
+
if ENV['CLASSPATH'] # if there is a CLASSPATH environment variable, let's use it.
|
7
|
+
ENV['CLASSPATH'].split(':').each do |string| # Add all class path env variables to the CLASSPATH as Pathnames
|
8
|
+
CLASSPATH.push( Pathname.new(string) )
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Remove duplicates
|
13
|
+
CLASSPATH.uniq!
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# A namespace to hold all exceptions defined by this library
|
2
|
+
module JavaHead::Exceptions
|
3
|
+
|
4
|
+
# a JavaHead exception
|
5
|
+
class JavaHeadException < StandardError
|
6
|
+
end
|
7
|
+
# General JavaHead::ClassException
|
8
|
+
class ClassException < JavaHeadException
|
9
|
+
end
|
10
|
+
# General JavaHead::Package exception
|
11
|
+
class PackageException < JavaHeadException
|
12
|
+
end
|
13
|
+
|
14
|
+
# Represents exceptions while compiling
|
15
|
+
class CompilerException < ClassException
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# Represents exceptions while running
|
20
|
+
class RunnerException < ClassException
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
|
4
|
+
module JavaHead
|
5
|
+
|
6
|
+
# The class to represent Java packages.
|
7
|
+
# Packages are immutable and duplicate package names are not allowed.
|
8
|
+
# To this end, the ::new method is private and packages are accessed using
|
9
|
+
# the ::get method which checks the class's internal cache prior to creating a new object
|
10
|
+
class Package
|
11
|
+
|
12
|
+
# Construct a package
|
13
|
+
# This method is private
|
14
|
+
#
|
15
|
+
# @param [String] name The Java name of the package
|
16
|
+
def initialize(name)
|
17
|
+
raise PackageException, "Package #{name} already exists" if @@stored[name.intern]
|
18
|
+
|
19
|
+
# Test name
|
20
|
+
raise PackageException, "Invalid package name #{name}" unless name.match FORMAT
|
21
|
+
|
22
|
+
|
23
|
+
names = name.split('.') # An array of the package names, we will be using this a lot
|
24
|
+
JavaHead::CLASSPATH.each do |base|
|
25
|
+
absolute = base.join(*names)
|
26
|
+
@path = absolute.realpath if absolute.exist? and absolute.directory?
|
27
|
+
end
|
28
|
+
raise PackageException, "Could not find directory for package #{name}" unless @path
|
29
|
+
|
30
|
+
|
31
|
+
# Set superpackage
|
32
|
+
@name = names.pop.freeze
|
33
|
+
if names.empty?
|
34
|
+
@superpackage = nil
|
35
|
+
else
|
36
|
+
@superpackage = self.class.get(names.join('.'))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# getter methods for name, superpackage, path
|
41
|
+
attr_reader :name,:superpackage,:path
|
42
|
+
|
43
|
+
# recursively compute fullname using superpackage fullname
|
44
|
+
#
|
45
|
+
# @return [String] The package's full name, e.g. com.example.packagename
|
46
|
+
def fullname
|
47
|
+
return @name unless @superpackage
|
48
|
+
"#{@superpackage.fullname}.#{@name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# to_s returns fullname
|
52
|
+
alias to_s fullname
|
53
|
+
|
54
|
+
# print useful fully-qualified name and path of class
|
55
|
+
#
|
56
|
+
# @return [String] A string that outlines the basic attributes of the object
|
57
|
+
def inspect
|
58
|
+
"[Java Package, name: #{fullname}, path: #{path}]"
|
59
|
+
end
|
60
|
+
|
61
|
+
# return a subpackage of the current package
|
62
|
+
#
|
63
|
+
# @param [String] name the name of the child package
|
64
|
+
# @return [JavaHead::Package] the child package
|
65
|
+
def subpackage(name)
|
66
|
+
Dir.chdir @path do
|
67
|
+
self.class.get("#{fullname}.#{name}")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# return a class within the current package
|
72
|
+
#
|
73
|
+
# @param [String] name the name of the class within the package
|
74
|
+
# @return [JavaHead::Class] the child class
|
75
|
+
def class(name=nil)
|
76
|
+
return super() if name.eql? nil
|
77
|
+
Dir.chdir @path do
|
78
|
+
JavaHead::Class.new("#{fullname}.#{name}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# get all classes in the current package
|
83
|
+
#
|
84
|
+
# @return [Array<JavaHead::Class>] all classes in the current package
|
85
|
+
def classes
|
86
|
+
Dir.chdir(@path) do
|
87
|
+
Dir.glob('*.java').map! do |filename|
|
88
|
+
self.class( filename.match(/^([A-Z][A-Za-z0-9]*)\.java$/)[1] )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# compile all classes in the package
|
94
|
+
#
|
95
|
+
# @return [JavaHead::Package] this package
|
96
|
+
def compile
|
97
|
+
classes.each { |c| c.compile }
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
# Check if all the classes in this package are compiled
|
102
|
+
#
|
103
|
+
# @return [Boolean] Whether or not all classes are compiled
|
104
|
+
def compiled?
|
105
|
+
classes.each do |jclass|
|
106
|
+
return false unless jclass.compiled?
|
107
|
+
end
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
# call #remove_class on all class files of the package
|
112
|
+
#
|
113
|
+
# @return [JavaHead::Package] the current value of this
|
114
|
+
def remove_class
|
115
|
+
classes.each { |c| c.remove_class }
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
# returns #class(name) or #subpackage(name) depending on the format of name
|
122
|
+
#
|
123
|
+
# @param [String] name the name of the member element
|
124
|
+
# @return [JavaHead::Package,JavaHead::Class] The child package or class
|
125
|
+
def member(name)
|
126
|
+
if name.match JavaHead::Class::FORMAT
|
127
|
+
self.class(name)
|
128
|
+
else
|
129
|
+
subpackage(name)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
# > is a handy operator alias for member
|
135
|
+
alias > member
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
# The required format for all package names
|
140
|
+
FORMAT = /^([a-z][a-z0-9]*\.)*[a-z_][a-z0-9_]*$/.freeze
|
141
|
+
@@stored = Hash.new
|
142
|
+
|
143
|
+
|
144
|
+
class << self
|
145
|
+
private :new
|
146
|
+
|
147
|
+
# Get the package that corresponds to name
|
148
|
+
#
|
149
|
+
# @param [String] name the name of the package
|
150
|
+
# @return [JavaHead::Package] the package that corresponds to name
|
151
|
+
def get(name)
|
152
|
+
sym = name.intern
|
153
|
+
return @@stored[sym] if @@stored[sym]
|
154
|
+
package = new(name)
|
155
|
+
@@stored[sym] = package
|
156
|
+
package
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
# include all JavaHead Exceptions
|
163
|
+
include JavaHead::Exceptions
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
data/lib/java_head/version.rb
CHANGED
data/lib/java_head.rb
CHANGED
@@ -9,289 +9,6 @@ require 'pathname'
|
|
9
9
|
# The namespace for the classes
|
10
10
|
module JavaHead
|
11
11
|
|
12
|
-
# The class to represent Java packages.
|
13
|
-
# Packages are immutable and duplicate package names are not allowed.
|
14
|
-
# To this end, the ::new method is private and packages are accessed using
|
15
|
-
# the ::get method which checks the class's internal cache prior to creating a new object
|
16
|
-
class Package
|
17
|
-
|
18
|
-
# Construct a package
|
19
|
-
# This method is private
|
20
|
-
#
|
21
|
-
# @param [String] name The Java name of the package
|
22
|
-
def initialize(name)
|
23
|
-
raise PackageException, "Package #{name} already exists" if @@stored[name.intern]
|
24
|
-
|
25
|
-
# Test name
|
26
|
-
raise PackageException, "Invalid package name #{name}" unless name.match FORMAT
|
27
|
-
|
28
|
-
|
29
|
-
names = name.split('.') # An array of the package names, we will be using this a lot
|
30
|
-
|
31
|
-
CLASSPATH.each do |base|
|
32
|
-
absolute = base.join(*names)
|
33
|
-
@path = absolute.realpath if absolute.exist? and absolute.directory?
|
34
|
-
end
|
35
|
-
raise PackageException, "Could not find directory for package #{name}" unless @path
|
36
|
-
|
37
|
-
|
38
|
-
# Set superpackage
|
39
|
-
@name = names.pop.freeze
|
40
|
-
if names.empty?
|
41
|
-
@superpackage = nil
|
42
|
-
else
|
43
|
-
@superpackage = self.class.get(names.join('.'))
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# getter methods for name, superpackage, path
|
48
|
-
attr_reader :name,:superpackage,:path
|
49
|
-
|
50
|
-
# recursively compute fullname using superpackage fullname
|
51
|
-
#
|
52
|
-
# @return [String] The package's full name, e.g. com.example.packagename
|
53
|
-
def fullname
|
54
|
-
return @name unless @superpackage
|
55
|
-
"#{@superpackage.fullname}.#{@name}"
|
56
|
-
end
|
57
|
-
|
58
|
-
# to_s returns fullname
|
59
|
-
alias to_s fullname
|
60
|
-
|
61
|
-
# print useful fully-qualified name and path of class
|
62
|
-
#
|
63
|
-
# @return [String] A string that outlines the basic attributes of the object
|
64
|
-
def inspect
|
65
|
-
"[Java Package, name: #{fullname}, path: #{path}]"
|
66
|
-
end
|
67
|
-
|
68
|
-
# return a subpackage of the current package
|
69
|
-
#
|
70
|
-
# @param [String] name the name of the child package
|
71
|
-
# @return [JavaHead::Package] the child package
|
72
|
-
def subpackage(name)
|
73
|
-
self.class.get("#{fullname}.#{name}")
|
74
|
-
end
|
75
|
-
|
76
|
-
# return a class within the current package
|
77
|
-
#
|
78
|
-
# @param [String] name the name of the class within the package
|
79
|
-
# @return [JavaHead::Class] the child class
|
80
|
-
def class(name=nil)
|
81
|
-
return super() if name.eql? nil
|
82
|
-
Class.new("#{fullname}.#{name}")
|
83
|
-
end
|
84
|
-
|
85
|
-
# get all classes in the current package
|
86
|
-
#
|
87
|
-
# @return [Array<JavaHead::Class>] all classes in the current package
|
88
|
-
def classes
|
89
|
-
Dir.chdir(@path) do
|
90
|
-
Dir.glob('*.java').map! do |filename|
|
91
|
-
self.class( filename.match(/^([A-Z][A-Za-z0-9]*)\.java$/)[1] )
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# compile all classes in the package
|
97
|
-
#
|
98
|
-
# @return [JavaHead::Package] this package
|
99
|
-
def compile
|
100
|
-
classes.each { |c| c.compile }
|
101
|
-
self
|
102
|
-
end
|
103
|
-
|
104
|
-
# Check if all the classes in this package are compiled
|
105
|
-
#
|
106
|
-
# @return [Boolean] Whether or not all classes are compiled
|
107
|
-
def compiled?
|
108
|
-
classes.each do |jclass|
|
109
|
-
return false unless jclass.compiled?
|
110
|
-
end
|
111
|
-
true
|
112
|
-
end
|
113
|
-
|
114
|
-
# call #remove_class on all class files of the package
|
115
|
-
#
|
116
|
-
# @return [JavaHead::Package] the current value of this
|
117
|
-
def remove_class
|
118
|
-
classes.each { |c| c.remove_class }
|
119
|
-
self
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
# returns #class(name) or #subpackage(name) depending on the format of name
|
125
|
-
#
|
126
|
-
# @param [String] name the name of the member element
|
127
|
-
# @return [JavaHead::Package,JavaHead::Class] The child package or class
|
128
|
-
def member(name)
|
129
|
-
if name.match Class::FORMAT
|
130
|
-
self.class(name)
|
131
|
-
else
|
132
|
-
subpackage(name)
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
# > is a handy operator alias for member
|
138
|
-
alias > member
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
# The required format for all package names
|
143
|
-
FORMAT = /^([a-z][a-z0-9]*\.)*[a-z_][a-z0-9_]*$/.freeze
|
144
|
-
@@stored = Hash.new
|
145
|
-
|
146
|
-
|
147
|
-
class << self
|
148
|
-
private :new
|
149
|
-
|
150
|
-
# Get the package that corresponds to name
|
151
|
-
#
|
152
|
-
# @param [String] name the name of the package
|
153
|
-
# @return [JavaHead::Package] the package that corresponds to name
|
154
|
-
def get(name)
|
155
|
-
sym = name.intern
|
156
|
-
return @@stored[sym] if @@stored[sym]
|
157
|
-
package = new(name)
|
158
|
-
@@stored[sym] = package
|
159
|
-
package
|
160
|
-
end
|
161
|
-
|
162
|
-
end
|
163
|
-
|
164
|
-
end
|
165
|
-
|
166
|
-
# Class to represent Java Classes
|
167
|
-
class Class
|
168
|
-
# Construct a new Class object
|
169
|
-
#
|
170
|
-
# @param [String] name the full name of the class
|
171
|
-
def initialize(name)
|
172
|
-
raise ClassException, "Invalid class name #{name}" unless name.match FORMAT
|
173
|
-
|
174
|
-
names = name.split('.')
|
175
|
-
@name = names.pop.freeze
|
176
|
-
@package = Package.get(names.join('.'))
|
177
|
-
@path = @package.path.join("#{@name}.java")
|
178
|
-
|
179
|
-
raise ClassException, "Location not found for class #{name}" unless @path.exist? and @path.file?
|
180
|
-
end
|
181
|
-
# name, package, and path are publicly visible
|
182
|
-
attr_reader :name, :package, :path
|
183
|
-
|
184
|
-
# Get the fully qualified name of the class
|
185
|
-
# @return [String] the full name of the class, e.g. com.example.projects.Circle
|
186
|
-
def fullname
|
187
|
-
"#{@package.fullname}.#{@name}"
|
188
|
-
end
|
189
|
-
|
190
|
-
# #to_s is #fullname
|
191
|
-
alias to_s fullname
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
# Compile the program
|
197
|
-
# Raises a CompilerException if there was a problem compiling
|
198
|
-
# @return [JavaHead::Class] this class object
|
199
|
-
def compile(*args)
|
200
|
-
remove_class if compiled?
|
201
|
-
command = 'javac '
|
202
|
-
args.each do |arg|
|
203
|
-
arg = arg.to_s
|
204
|
-
raise CompilerException, "Invalid compiling argument #{arg}" unless arg.match ARGFORMAT
|
205
|
-
end
|
206
|
-
command << args.join(' ')
|
207
|
-
command << ' '
|
208
|
-
command << @path.to_s
|
209
|
-
output = `#{command}`
|
210
|
-
raise CompilerException, "Class #{fullname} could not compile" unless compiled?
|
211
|
-
self
|
212
|
-
end
|
213
|
-
|
214
|
-
# Remove the existing compiled class
|
215
|
-
#
|
216
|
-
# @return [JavaHead::Class, Boolean] this class object or false if not successful
|
217
|
-
def remove_class
|
218
|
-
Dir.chdir(@package.path) do
|
219
|
-
Pathname.glob("#{@name}$*.class") do |pathname|
|
220
|
-
pathname.unlink
|
221
|
-
end
|
222
|
-
Pathname.new("#{@name}.class").unlink
|
223
|
-
end
|
224
|
-
self
|
225
|
-
|
226
|
-
# the file doesn't exist or there was a problem loading it
|
227
|
-
rescue Errno::ENOENT
|
228
|
-
return false
|
229
|
-
end
|
230
|
-
|
231
|
-
# Test to see if compilation works, args are passed to the compile method
|
232
|
-
#
|
233
|
-
# @param [Array] args the arguments to be passed to the #compile method
|
234
|
-
# @return [JavaHead::Class,NilClass] this class object or nil if the compilation failed
|
235
|
-
def test(*args)
|
236
|
-
compile(*args)
|
237
|
-
remove_class
|
238
|
-
self
|
239
|
-
rescue Exception => e
|
240
|
-
puts "Exception of type #{e.class} while compiling #{fullname}: #{e}"
|
241
|
-
nil
|
242
|
-
end
|
243
|
-
|
244
|
-
# Integrated compile, run, remove_class
|
245
|
-
# This method assumes to some extent that
|
246
|
-
# compilation will succeed, so although this may fail,
|
247
|
-
# its arguments are passed to the exec method
|
248
|
-
#
|
249
|
-
# @param [Array] args the arguments to be passed to the #exec method
|
250
|
-
# @return [String] the output created by the Java program
|
251
|
-
def run(*args)
|
252
|
-
compile # this is a simple list of things for the interpreter to do
|
253
|
-
output = exec *args
|
254
|
-
remove_class
|
255
|
-
output # return output
|
256
|
-
end
|
257
|
-
|
258
|
-
# Check if the class is compiled?
|
259
|
-
#
|
260
|
-
# @return [Boolean] whether or not the class compiled
|
261
|
-
def compiled?
|
262
|
-
@path.dirname.join("#{@name}.class").exist?
|
263
|
-
end
|
264
|
-
|
265
|
-
# Take given command line arguments, check them for validity, add them to a java command and run the command to execute the class
|
266
|
-
#
|
267
|
-
# @param [Array] args the command-line arguments to be passed to the Java program
|
268
|
-
# @return [String] the output of the program execution
|
269
|
-
def exec(*args)
|
270
|
-
raise RunnerException, "Class #{fullname} cannot be run because it is not compiled" unless compiled?
|
271
|
-
command = "java #{fullname}"
|
272
|
-
args.each do |arg|
|
273
|
-
arg = arg.to_s
|
274
|
-
raise RunnerException, "Invalid command-line argument: #{arg}" unless arg.match ARGFORMAT
|
275
|
-
command << ' '
|
276
|
-
command << arg
|
277
|
-
end
|
278
|
-
`#{command}`
|
279
|
-
end
|
280
|
-
|
281
|
-
# Inspect incorporates meaningful data like name, location and whether class is compiled
|
282
|
-
# @return [String] useful data about the current object
|
283
|
-
def inspect
|
284
|
-
"[Java Class, name: #{fullname}, path: #{@path}, #{ compiled? ? 'Compiled' : 'Not Compiled'}]"
|
285
|
-
end
|
286
|
-
|
287
|
-
# The format for command-line arguments
|
288
|
-
ARGFORMAT = /^[\-a-zA-Z@][a-zA-Z0-9\-:="'@]*$/.freeze
|
289
|
-
# The format for classnames, e.g. com.example.projects.Shape
|
290
|
-
FORMAT = /^([a-z_][a-z0-9_]*\.)*[A-Z][a-z0-9_]*$/.freeze
|
291
|
-
|
292
|
-
|
293
|
-
end
|
294
|
-
|
295
12
|
# Methods in the eigenclass of Java
|
296
13
|
class << self
|
297
14
|
# Find a package using Package.get
|
@@ -299,7 +16,7 @@ module JavaHead
|
|
299
16
|
# @param [String] name the name of the package to be found
|
300
17
|
# @return [JavaHead::Package] the package corresponding to name
|
301
18
|
def package(name)
|
302
|
-
Package.get(name)
|
19
|
+
JavaHead::Package.get(name)
|
303
20
|
end
|
304
21
|
|
305
22
|
# Returns the class with no arguments
|
@@ -309,7 +26,7 @@ module JavaHead
|
|
309
26
|
# @return [JavaHead::Class] the resulting class
|
310
27
|
def class(name = nil)
|
311
28
|
return super() if name.eql? nil
|
312
|
-
Class.new(name)
|
29
|
+
JavaHead::Class.new(name)
|
313
30
|
end
|
314
31
|
|
315
32
|
# Creates either a class or a package
|
@@ -318,7 +35,7 @@ module JavaHead
|
|
318
35
|
# @param [String] name the name of the child element
|
319
36
|
# @return [JavaHead::Package, JavaHead::Class] the resulting package or class object
|
320
37
|
def member(name)
|
321
|
-
if name.match Class::FORMAT
|
38
|
+
if name.match JavaHead::Class::FORMAT
|
322
39
|
self.class(name)
|
323
40
|
else
|
324
41
|
package(name)
|
@@ -327,35 +44,22 @@ module JavaHead
|
|
327
44
|
|
328
45
|
# > is an alias for member
|
329
46
|
alias > member
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
47
|
+
|
48
|
+
# Try to load the file const_name if the constant cannot be found
|
49
|
+
#
|
50
|
+
# @param [String] const_name
|
51
|
+
# @return [Regexp,Array,Class] the value of the constant const_name in the namespace of JavaHead
|
52
|
+
def const_missing(const_name)
|
53
|
+
require "#{__dir__}/java_head/#{const_name.to_s.downcase}.rb"
|
54
|
+
return const_get const_name
|
55
|
+
rescue LoadError
|
56
|
+
super
|
339
57
|
end
|
58
|
+
|
340
59
|
end
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
# General Java::Class exception
|
345
|
-
class ClassException < StandardError
|
346
|
-
end
|
347
|
-
# General Java::Package exception
|
348
|
-
class PackageException < StandardError
|
349
|
-
end
|
350
|
-
|
351
|
-
# Represents exceptions while compiling
|
352
|
-
class CompilerException < StandardError
|
353
|
-
end
|
354
|
-
|
355
|
-
|
356
|
-
# Represents exceptions while running
|
357
|
-
class RunnerException < StandardError
|
358
|
-
end
|
60
|
+
|
61
|
+
|
62
|
+
|
359
63
|
|
360
64
|
end
|
361
65
|
|
data/test/test_class.rb
CHANGED
@@ -6,9 +6,10 @@ require 'java_head'
|
|
6
6
|
class TestClass < MiniTest::Test
|
7
7
|
|
8
8
|
def setup
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Dir.chdir("#{__dir__}/src") do
|
10
|
+
@safe = JavaHead::Class.new('com.example.projects.safe.Safe')
|
11
|
+
@broken = JavaHead::Class.new('com.example.projects.broken.Broken')
|
12
|
+
end
|
12
13
|
end
|
13
14
|
|
14
15
|
def test_safe_class_should_compile
|
@@ -26,7 +27,7 @@ class TestClass < MiniTest::Test
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def test_broken_class_should_not_compile
|
29
|
-
assert_raises JavaHead::CompilerException do
|
30
|
+
assert_raises JavaHead::Exceptions::CompilerException do
|
30
31
|
puts
|
31
32
|
puts 'THE FOLLOWING JAVA ERROR IS EXPECTED, WE ARE TESTING THAT BROKEN CLASSES SHOULD NOT COMPILE'
|
32
33
|
@broken.compile()
|
@@ -37,4 +38,4 @@ class TestClass < MiniTest::Test
|
|
37
38
|
|
38
39
|
|
39
40
|
|
40
|
-
end
|
41
|
+
end
|
data/test/test_package.rb
CHANGED
@@ -3,8 +3,9 @@ require 'java_head'
|
|
3
3
|
|
4
4
|
class TestPackage < MiniTest::Test
|
5
5
|
def setup
|
6
|
-
|
7
|
-
|
6
|
+
Dir.chdir "#{__dir__}/src" do
|
7
|
+
@package = JavaHead::Package.get 'com.example'
|
8
|
+
end
|
8
9
|
end
|
9
10
|
|
10
11
|
def test_package_should_match_directory
|
@@ -23,11 +24,11 @@ class TestPackage < MiniTest::Test
|
|
23
24
|
|
24
25
|
def test_broken_package_should_not_compile
|
25
26
|
pkg = @package > 'projects.broken'
|
26
|
-
assert_raises JavaHead::CompilerException do
|
27
|
+
assert_raises JavaHead::Exceptions::CompilerException do
|
27
28
|
pkg.compile
|
28
29
|
end
|
29
30
|
refute pkg.compiled?
|
30
31
|
end
|
31
32
|
|
32
33
|
|
33
|
-
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: java_head
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndrewTLee
|
@@ -82,7 +82,12 @@ files:
|
|
82
82
|
- Rakefile
|
83
83
|
- java_head.gemspec
|
84
84
|
- lib/java_head.rb
|
85
|
+
- lib/java_head/class.rb
|
86
|
+
- lib/java_head/classpath.rb
|
87
|
+
- lib/java_head/exceptions.rb
|
88
|
+
- lib/java_head/package.rb
|
85
89
|
- lib/java_head/version.rb
|
90
|
+
- lib/java_head/version.rb~
|
86
91
|
- test/src/com/example/projects/broken/Broken.java
|
87
92
|
- test/src/com/example/projects/safe/Safe.java
|
88
93
|
- test/test_class.rb
|