rubinius-core-api 0.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt ADDED
@@ -0,0 +1,20 @@
1
+ This is an attempt to provide some of Rubinius's additional core classes on
2
+ other implementations.
3
+
4
+ Rubinius has all the normal Ruby classes, but to support implementing them
5
+ mostly in Ruby, they have added a number of other support classes. This
6
+ library hopes to implement those additional support classes for other Ruby
7
+ implementations, so they their utility can be shared across implementations.
8
+
9
+ Currently, only the following classes are implemented, and only on JRuby:
10
+
11
+ Rubinius::ByteArray - a fixed-size array of bytes
12
+ Rubinius::Channel - a low-level synchronization mechanism
13
+ Rubinius::EnvironmentAccess - env variable support
14
+ Rubinius::Tuple - a fixed-size array of object references
15
+ Rubinius::Type - utilities for type conversions
16
+
17
+ In addition, some utility methods added to Thread for recursive guards and
18
+ Kernel::StringValue are also implemented.
19
+
20
+ More APIs will be added over time.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ task :default => :spec
2
+
3
+ if defined?(JRUBY_VERSION)
4
+ require 'ant'
5
+
6
+ directory "pkg/classes"
7
+
8
+ desc "Clean up build artifacts"
9
+ task :clean do
10
+ rm_rf "pkg/classes"
11
+ rm_rf "lib/rubinius-core-api.jar"
12
+ end
13
+
14
+ desc "Compile the extension"
15
+ task :compile => "pkg/classes" do |t|
16
+ ant.javac :srcdir => "src", :destdir => t.prerequisites.first,
17
+ :source => "1.5", :target => "1.5", :debug => true,
18
+ :classpath => "${java.class.path}:${sun.boot.class.path}"
19
+ end
20
+
21
+ desc "Build the jar"
22
+ task :jar => :compile do
23
+ ant.jar :basedir => "pkg/classes", :destfile => "lib/rubinius-core-api.jar", :includes => "**/*.class"
24
+ end
25
+
26
+ task :package => :jar
27
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
28
+ task :package do
29
+ # nop
30
+ end
31
+ end
32
+
33
+ desc "Run the specs"
34
+ task :spec => :package do
35
+ ruby "-S", "rspec", "spec"
36
+ end
Binary file
@@ -0,0 +1,16 @@
1
+ if defined?(JRUBY_VERSION)
2
+ begin
3
+ require 'rubinius-core-api.jar'
4
+ rescue LoadError
5
+ # keep going; might be bundled into classpath already
6
+ end
7
+
8
+ # for access to JRuby runtime
9
+ require 'jruby'
10
+
11
+ org.jruby.ext.rubinius.RubiniusLibrary.new.load(JRuby.runtime, false)
12
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
13
+ # do nothing for Rubinius
14
+ else
15
+ raise "Only supported on JRuby and Rubinius"
16
+ end
@@ -0,0 +1,106 @@
1
+ ##
2
+ # Channel is a FIFO, thread-aware value passing class that can hold any number
3
+ # of objects similar to Queue. Use #send to add objects to the channel and
4
+ # #receive to remove objects from the channel.
5
+ #
6
+ # If Channel#receive is called on an empty channel, the VM puts the current
7
+ # Thread (t1) to sleep. At some future time, when Channel#send is called on
8
+ # that same thread, the VM wakes up t1 and the value passed to #send is
9
+ # returned. This allows us to implement all manner of Thread semantics, such
10
+ # as Mutex.
11
+ #
12
+ # Channel is used heavily by Scheduler, to allow ruby code to interact with
13
+ # the outside world in a thread aware manner.
14
+
15
+ module Rubinius
16
+ class Channel
17
+
18
+ ##
19
+ # Returns nil if nothing is waiting, or a List object which contains all
20
+ # Thread objects waiting on this Channel.
21
+
22
+ attr_reader :waiting
23
+
24
+ ##
25
+ # Returns nil if there are no values, otherwise a List object containing all
26
+ # values the Channel contains.
27
+
28
+ attr_reader :value
29
+
30
+ ##
31
+ # Creates a new Channel and registers it with the VM.
32
+
33
+ def self.new
34
+ Ruby.primitive :channel_new
35
+ raise PrimitiveFailure, "Channel.new primitive failed"
36
+ end
37
+
38
+ # We must be sure a Channel is always created properly, so handle
39
+ # this the same as new.
40
+ def self.allocate
41
+ Ruby.primitive :channel_new
42
+ raise PrimitiveFailure, "Channel.new primitive failed"
43
+ end
44
+
45
+ ##
46
+ # Puts +obj+ in the Channel. If there are waiting threads the first thread
47
+ # will be woken up and handed +obj+.
48
+
49
+ def send(obj)
50
+ Ruby.primitive :channel_send
51
+ raise PrimitiveFailure, "Channel#send primitive failed"
52
+ end
53
+
54
+ alias_method :<<, :send
55
+
56
+ ##
57
+ # Removes and returns the first value from the Channel. If the channel
58
+ # is empty, Thread.current is put to sleep until #send is called.
59
+
60
+ def receive
61
+ Ruby.primitive :channel_receive
62
+ raise PrimitiveFailure, "Channel#receive primitive failed"
63
+ end
64
+
65
+ def receive_timeout(duration)
66
+ Ruby.primitive :channel_receive_timeout
67
+ raise PrimitiveFailure, "Channel#receive_timeout primitive failed"
68
+ end
69
+
70
+ def try_receive
71
+ Ruby.primitive :channel_try_receive
72
+ raise PrimitiveFailure, "Channel#try_receive primitive failed"
73
+ end
74
+
75
+ ##
76
+ # Converts +obj+ into a Channel using #to_channel.
77
+
78
+ def self.convert_to_channel(obj)
79
+ return obj if Channel === obj
80
+ begin
81
+ o2 = obj.to_channel
82
+ unless Channel === o2
83
+ raise ArgumentError, "to_channel on #{obj.inspect} did not return a Channel"
84
+ end
85
+ return o2
86
+ rescue NoMethodError
87
+ raise ArgumentError, "Unable to convert #{obj.inspect} into a channel"
88
+ end
89
+ end
90
+
91
+ ##
92
+ # Legacy API. To be removed.
93
+
94
+ def self.receive(obj) # :nodoc:
95
+ return convert_to_channel(obj).receive
96
+ end
97
+
98
+ ##
99
+ # API compliance, returns self.
100
+
101
+ def to_channel
102
+ self
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,26 @@
1
+ ##
2
+ # An array of bytes, used as a low-level data store for implementing various
3
+ # other classes.
4
+
5
+ class Rubinius::ByteArray
6
+ alias_method :[], :get_byte
7
+ alias_method :[]=, :set_byte
8
+
9
+ def each
10
+ i = 0
11
+ max = size()
12
+
13
+ while i < max
14
+ yield get_byte(i)
15
+ i += 1
16
+ end
17
+ end
18
+
19
+ def inspect
20
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{size} bytes>"
21
+ end
22
+
23
+ def <=>(other)
24
+ compare_bytes other, size, other.size
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ ##
2
+ # A communication mechanism based on pi-calculus channels used primarily to
3
+ # communicate between ruby and the VM about events.
4
+
5
+ module Rubinius
6
+ class Channel
7
+ def inspect
8
+ "#<Rubinius::Channel>"
9
+ end
10
+
11
+ def as_lock(val=nil)
12
+ receive
13
+
14
+ begin
15
+ yield
16
+ ensure
17
+ self << val
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,239 @@
1
+ ##
2
+ # Interface to process environment variables.
3
+
4
+ module Rubinius
5
+ class EnvironmentVariables
6
+ include Enumerable
7
+ include Rubinius::EnvironmentAccess
8
+
9
+ def [](key)
10
+ getenv(StringValue(key)).freeze
11
+ end
12
+
13
+ def []=(key, value)
14
+ key = StringValue(key)
15
+ if value.nil?
16
+ unsetenv(key)
17
+ else
18
+ setenv key, StringValue(value), 1
19
+ end
20
+ value
21
+ end
22
+
23
+ alias_method :store, :[]=
24
+
25
+ def each_key
26
+ return to_enum(:each_key) unless block_given?
27
+
28
+ each { |k, v| yield k }
29
+ end
30
+
31
+ def each_value
32
+ return to_enum(:each_value) unless block_given?
33
+
34
+ each { |k, v| yield v }
35
+ end
36
+
37
+ def each
38
+ return to_enum(:each) unless block_given?
39
+
40
+ env = environ()
41
+ ptr_size = FFI.type_size FFI.find_type(:pointer)
42
+
43
+ i = 0
44
+
45
+ offset = 0
46
+ cur = env + offset
47
+
48
+ until cur.read_pointer.null?
49
+ entry = cur.read_pointer.read_string
50
+ key, value = entry.split '=', 2
51
+ value.taint if value
52
+ key.taint if key
53
+
54
+ yield key, value
55
+
56
+ offset += ptr_size
57
+ cur = env + offset
58
+ end
59
+
60
+ self
61
+ end
62
+
63
+ alias_method :each_pair, :each
64
+
65
+ def delete(key)
66
+ existing_value = self[key]
67
+ self[key] = nil if existing_value
68
+ existing_value
69
+ end
70
+
71
+ def delete_if(&block)
72
+ return to_enum(:delete_it) unless block_given?
73
+ reject!(&block)
74
+ self
75
+ end
76
+
77
+ def fetch(key, absent=undefined)
78
+ if block_given? and !absent.equal?(undefined)
79
+ warn "block supersedes default value argument"
80
+ end
81
+
82
+ if value = self[key]
83
+ return value
84
+ end
85
+
86
+ if block_given?
87
+ return yield(key)
88
+ elsif absent.equal?(undefined)
89
+ raise IndexError, "key not found"
90
+ end
91
+
92
+ return absent
93
+ end
94
+
95
+ def include?(key)
96
+ !self[key].nil?
97
+ end
98
+
99
+ alias_method :has_key?, :include?
100
+ alias_method :key?, :include?
101
+ # More efficient than using the one from Enumerable
102
+ alias_method :member?, :include?
103
+
104
+ def to_s
105
+ "ENV"
106
+ end
107
+
108
+ def inspect
109
+ to_hash.inspect
110
+ end
111
+
112
+ def reject(&block)
113
+ to_hash.reject(&block)
114
+ end
115
+
116
+ def reject!
117
+ return to_enum(:reject!) unless block_given?
118
+
119
+ rejected = false
120
+ each do |k, v|
121
+ if yield(k, v)
122
+ delete k
123
+ rejected = true
124
+ end
125
+ end
126
+
127
+ rejected ? self : nil
128
+ end
129
+
130
+ def clear
131
+ # Avoid deleting from environ while iterating because the
132
+ # OS can handle that in a million different bad ways.
133
+
134
+ keys = []
135
+ each { |k,v| keys << k }
136
+ keys.each { |k| delete k }
137
+
138
+ self
139
+ end
140
+
141
+ def has_value?(value)
142
+ each { |k,v| return true if v == value }
143
+ return false
144
+ end
145
+
146
+ alias_method :value?, :has_value?
147
+
148
+ def values_at(*params)
149
+ params.map{ |k| self[k] }
150
+ end
151
+
152
+ def index(value)
153
+ each do |k, v|
154
+ return k if v == value
155
+ end
156
+ nil
157
+ end
158
+
159
+ def invert
160
+ to_hash.invert
161
+ end
162
+
163
+ def keys
164
+ keys = []
165
+ each { |k,v| keys << k }
166
+ keys
167
+ end
168
+
169
+ def values
170
+ vals = []
171
+ each { |k,v| vals << v }
172
+ vals
173
+ end
174
+
175
+ def empty?
176
+ each { return false }
177
+ return true
178
+ end
179
+
180
+ def length
181
+ sz = 0
182
+ each { |k,v| sz += 1 }
183
+ sz
184
+ end
185
+
186
+ alias_method :size, :length
187
+
188
+ def rehash
189
+ # No need to do anything, our keys are always strings
190
+ end
191
+
192
+ def replace(other)
193
+ clear
194
+ other.each { |k, v| self[k] = v }
195
+ end
196
+
197
+ def shift
198
+ env = environ()
199
+ ptr_size = FFI.type_size FFI.find_type(:pointer)
200
+
201
+ offset = 0
202
+ cur = env + offset
203
+
204
+ ptr = cur.read_pointer
205
+ return nil unless ptr
206
+
207
+ key, value = ptr.read_string.split "=", 2
208
+
209
+ return nil unless key
210
+
211
+ key.taint if key
212
+ value.taint if value
213
+
214
+ delete key
215
+
216
+ return [key, value]
217
+ end
218
+
219
+ def to_a
220
+ ary = []
221
+ each { |k,v| ary << [k,v] }
222
+ ary
223
+ end
224
+
225
+ def to_hash
226
+ return environ_as_hash()
227
+ end
228
+
229
+ def update(other, &block)
230
+ if block_given?
231
+ other.each { |k, v| self[k] = yield(k, self[k], v) }
232
+ else
233
+ other.each { |k, v| self[k] = v }
234
+ end
235
+ end
236
+
237
+ # Missing and deprecated: indexes, indices
238
+ end
239
+ end