svn 0.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.
- data/README +39 -0
- data/lib/svn.rb +19 -0
- data/lib/svn/apr_utils.rb +313 -0
- data/lib/svn/counted_strings.rb +38 -0
- data/lib/svn/diffs.rb +209 -0
- data/lib/svn/errors.rb +83 -0
- data/lib/svn/logs.rb +120 -0
- data/lib/svn/misc.rb +68 -0
- data/lib/svn/pools.rb +67 -0
- data/lib/svn/repos.rb +333 -0
- data/lib/svn/revisions.rb +133 -0
- data/lib/svn/roots.rb +161 -0
- data/lib/svn/streams.rb +149 -0
- data/lib/svn/transactions.rb +51 -0
- data/lib/svn/utils.rb +249 -0
- metadata +71 -0
data/lib/svn/utils.rb
ADDED
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module Svn #:nodoc:
|
5
|
+
|
6
|
+
# Utility functions for working with FFI
|
7
|
+
module Utils
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Returns a pointer to the object_id of +obj+
|
12
|
+
def wrap( obj )
|
13
|
+
ptr = FFI::MemoryPointer.new( :uint64 )
|
14
|
+
ptr.write_uint64( obj.object_id )
|
15
|
+
ptr
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the object for the object_id stored in +ptr+
|
19
|
+
def unwrap( ptr )
|
20
|
+
ObjectSpace._id2ref( ptr.read_uint64 )
|
21
|
+
end
|
22
|
+
|
23
|
+
# a generic factory class for use with FFI data types that adds default
|
24
|
+
# arguments to constructor calls
|
25
|
+
#
|
26
|
+
# # when NativeHash is created, the args are [ptr, :string, :string]
|
27
|
+
# bind :get_hash, :returning => NativeHash.factory( :string, :string )
|
28
|
+
class Factory
|
29
|
+
|
30
|
+
# factories also work as DataConverters so they can be used with FFI
|
31
|
+
include FFI::DataConverter
|
32
|
+
|
33
|
+
def initialize( klass, *args )
|
34
|
+
@klass = klass
|
35
|
+
@added_args = args
|
36
|
+
end
|
37
|
+
|
38
|
+
def new( *args )
|
39
|
+
@klass.new( *args, *@added_args )
|
40
|
+
end
|
41
|
+
|
42
|
+
def from_native( ptr, ctx )
|
43
|
+
@klass.new( ptr, *@added_args )
|
44
|
+
end
|
45
|
+
|
46
|
+
def native_type
|
47
|
+
@klass.native_type
|
48
|
+
end
|
49
|
+
|
50
|
+
def real_class
|
51
|
+
@klass
|
52
|
+
end
|
53
|
+
|
54
|
+
def size
|
55
|
+
@klass.size
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# returns the *contents* of the pointer as type
|
60
|
+
#
|
61
|
+
# for example:
|
62
|
+
# # void get_string( char **p ):
|
63
|
+
# get_string( out_ptr ); content_for( out_ptr, :string )
|
64
|
+
#
|
65
|
+
# # void get_hash( hash_t **p ):
|
66
|
+
# class Hash < FFI::AutoPointer; end
|
67
|
+
# get_hash( out_ptr ); content_for( out_ptr, Hash )
|
68
|
+
#
|
69
|
+
# if the type is a FFI::Pointer, this will try to instantiate it; to avoid
|
70
|
+
# instantiation, pass :pointer as the type
|
71
|
+
def content_from( pointer, type, len=nil )
|
72
|
+
return if pointer.nil?
|
73
|
+
if type.is_a? Array
|
74
|
+
type.inject( pointer ) do |ptr, subtype|
|
75
|
+
content_for( ptr, subtype, len )
|
76
|
+
end
|
77
|
+
elsif type.is_a? Factory
|
78
|
+
type.new( pointer.read_pointer ) unless pointer.null?
|
79
|
+
elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
|
80
|
+
type.new( pointer.read_pointer ) unless pointer.null?
|
81
|
+
elsif type.is_a?( FFI::Type::Mapped )
|
82
|
+
type.from_native( pointer.read_pointer, nil ) unless pointer.null?
|
83
|
+
elsif type == :string
|
84
|
+
pointer.read_pointer.read_string(
|
85
|
+
( len == -1 ) ? nil : len
|
86
|
+
) unless pointer.null?
|
87
|
+
else
|
88
|
+
pointer.send( :"read_#{type}" )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# returns the the pointer's value as type
|
93
|
+
#
|
94
|
+
# for example:
|
95
|
+
# # char *get_string( void ):
|
96
|
+
# ptr = get_string()
|
97
|
+
# str = content_for( ptr, :string )
|
98
|
+
#
|
99
|
+
# # hash *get_hash( void ):
|
100
|
+
# class Hash < FFI::AutoPointer; end
|
101
|
+
# ptr = get_hash( out_ptr )
|
102
|
+
# hash = content_for( out_ptr, Hash )
|
103
|
+
def content_for( pointer, type, len=nil )
|
104
|
+
return if pointer.nil?
|
105
|
+
if type.is_a? Array
|
106
|
+
type.inject( pointer ) do |ptr, subtype|
|
107
|
+
content_for( ptr, subtype, len )
|
108
|
+
end
|
109
|
+
elsif type.is_a? Factory
|
110
|
+
type.new( pointer ) unless pointer.null?
|
111
|
+
elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
|
112
|
+
type.new( pointer ) unless pointer.null?
|
113
|
+
elsif type.is_a?( FFI::Type::Mapped )
|
114
|
+
type.from_native( pointer, nil ) unless pointer.null?
|
115
|
+
elsif type == :string
|
116
|
+
# if len is nil or -1, use it for reading instead of counting on it to
|
117
|
+
# be null-terminated
|
118
|
+
pointer.read_string( ( len == -1 ) ? nil : len ) unless pointer.null?
|
119
|
+
else
|
120
|
+
pointer.send( :"read_#{type}" ) unless pointer.null?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def pointer_for( value, type )
|
125
|
+
if type.is_a? Array
|
126
|
+
type.reverse.inject( value ) do |val, subtype|
|
127
|
+
pointer_for( val, subtype )
|
128
|
+
end
|
129
|
+
elsif type.is_a? Factory
|
130
|
+
pointer_for( value, type.real_class )
|
131
|
+
elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
|
132
|
+
# use val directly
|
133
|
+
value
|
134
|
+
elsif type.is_a?( FFI::Type::Mapped )
|
135
|
+
# mapped types are really pointers to structs; they are read
|
136
|
+
# differently, but they should still be pointers we can use directly
|
137
|
+
value
|
138
|
+
elsif type == :string
|
139
|
+
# use from_string even if it isn't necessary to null-terminate
|
140
|
+
FFI::MemoryPointer.from_string( value )
|
141
|
+
else
|
142
|
+
# it must be a FFI type, use a new MemoryPointer
|
143
|
+
ptr = FFI::MemoryPointer.new( type )
|
144
|
+
ptr.send( :"write_#{type}", value )
|
145
|
+
ptr
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# this module contains extensions for classes that inherit from FFI::Struct
|
150
|
+
# and FFI::AutoPointer to make binding instance methods to C methods more
|
151
|
+
# concise
|
152
|
+
module Extensions
|
153
|
+
|
154
|
+
# convenience method that returns a Factory instance for self with the
|
155
|
+
# given args
|
156
|
+
#
|
157
|
+
# the following are equivalent:
|
158
|
+
# NativeHash.factory( :string, :string )
|
159
|
+
#
|
160
|
+
# Factory( NativeHash, :string, :string )
|
161
|
+
def factory( *args )
|
162
|
+
Factory.new( self, *args )
|
163
|
+
end
|
164
|
+
|
165
|
+
module_function
|
166
|
+
|
167
|
+
# sets the module that will be used for all bound methods, until bind_to
|
168
|
+
# is called again
|
169
|
+
def bind_to( target )
|
170
|
+
@@target = target
|
171
|
+
end
|
172
|
+
|
173
|
+
# binds a method on the current target to self
|
174
|
+
#
|
175
|
+
# == arguments
|
176
|
+
# +sym+ :: the method on the target (set by +bind_to+) to use
|
177
|
+
# +options+ :: a Hash of optional method aliases or returned arguments
|
178
|
+
#
|
179
|
+
# == options
|
180
|
+
# +:as+ :: method name to use for the bound method
|
181
|
+
# +:to+ :: function name to use from the target object
|
182
|
+
# +:returning+ :: an array of types for out parameters
|
183
|
+
# +:validate+ :: a validation to call on the bound method's return value
|
184
|
+
# +:before_return+ :: a function to call on the return value
|
185
|
+
#
|
186
|
+
# TODO: call to_proc on symbols that should be procs
|
187
|
+
def bind( sym, options={}, &block )
|
188
|
+
# look up the method in the target module
|
189
|
+
meth_name = ( options[:to] || sym ).to_sym
|
190
|
+
# get a method obj from the target receiver so that if @@target is
|
191
|
+
# changed by another call to :bind_to, the method/target will not be
|
192
|
+
# changed (and broken)
|
193
|
+
meth = @@target.method( meth_name )
|
194
|
+
name = ( options[:as] || sym ).to_sym
|
195
|
+
|
196
|
+
# get the return types as an Array and save a copy
|
197
|
+
single_return = !options[:returning].is_a?( Array )
|
198
|
+
return_types = Array( options[:returning] ).dup
|
199
|
+
|
200
|
+
# get the C function validation
|
201
|
+
validation = options[:validate]
|
202
|
+
|
203
|
+
# get the before_return filter
|
204
|
+
before_return = options[:before_return] || lambda { |x| x }
|
205
|
+
|
206
|
+
# create a new method; blocks are used to re-arrange arguments
|
207
|
+
define_method( name ) do |*args|
|
208
|
+
# create new pointers for the specified out arguments
|
209
|
+
return_ptrs = return_types.map { |type| FFI::MemoryPointer.new( type ) }
|
210
|
+
|
211
|
+
return_val = nil # keep it in scope
|
212
|
+
if block
|
213
|
+
# call the method with the arguments after re-arranging via block
|
214
|
+
return_val = meth.call( *instance_exec(
|
215
|
+
*return_ptrs, self, *args, &block
|
216
|
+
) )
|
217
|
+
else
|
218
|
+
# call the method with the standard argument order
|
219
|
+
return_val = meth.call( *return_ptrs, self, *args )
|
220
|
+
end
|
221
|
+
|
222
|
+
# call the return check, if present
|
223
|
+
instance_exec( return_val, &validation ) if validation
|
224
|
+
|
225
|
+
# if there are return types (out pointers), read the values out of
|
226
|
+
# the pointers and replace the return_val
|
227
|
+
unless return_types.empty?
|
228
|
+
return_val = return_ptrs.zip( return_types ).map do |ptr, type|
|
229
|
+
Utils.content_from( ptr, type )
|
230
|
+
end
|
231
|
+
return_val = return_val.first if single_return
|
232
|
+
end
|
233
|
+
|
234
|
+
# run the before_return filter and return the value from it; if no
|
235
|
+
# :before_return was in options, this will be the id function
|
236
|
+
instance_exec( return_val, &before_return )
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
# extend FFI objects with the new helper methods
|
244
|
+
#FFI::Struct.extend Extensions
|
245
|
+
FFI::AutoPointer.extend Extensions
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: svn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Blue
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-11 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ffi
|
16
|
+
requirement: &15276700 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *15276700
|
25
|
+
description:
|
26
|
+
email: rdblue@gmail.com
|
27
|
+
executables: []
|
28
|
+
extensions: []
|
29
|
+
extra_rdoc_files:
|
30
|
+
- README
|
31
|
+
files:
|
32
|
+
- lib/svn/misc.rb
|
33
|
+
- lib/svn/pools.rb
|
34
|
+
- lib/svn/apr_utils.rb
|
35
|
+
- lib/svn/diffs.rb
|
36
|
+
- lib/svn/utils.rb
|
37
|
+
- lib/svn/transactions.rb
|
38
|
+
- lib/svn/logs.rb
|
39
|
+
- lib/svn/roots.rb
|
40
|
+
- lib/svn/repos.rb
|
41
|
+
- lib/svn/streams.rb
|
42
|
+
- lib/svn/errors.rb
|
43
|
+
- lib/svn/revisions.rb
|
44
|
+
- lib/svn/counted_strings.rb
|
45
|
+
- lib/svn.rb
|
46
|
+
- README
|
47
|
+
homepage: http://github.com/codefoundry/svn
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.10
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Ruby bindings for SVN based on FFI
|
71
|
+
test_files: []
|