sprsquish-blather 0.1 → 0.2.3
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/LICENSE +2 -0
- data/README.rdoc +100 -0
- data/Rakefile +110 -0
- data/examples/drb_client.rb +5 -0
- data/examples/echo.rb +18 -0
- data/ext/extconf.rb +65 -0
- data/ext/push_parser.c +231 -0
- data/lib/blather/client.rb +219 -44
- data/lib/blather/{core/sugar.rb → core_ext/active_support.rb} +25 -13
- data/lib/blather/core_ext/libxml.rb +28 -0
- data/lib/blather/errors/sasl_error.rb +87 -0
- data/lib/blather/errors/stanza_error.rb +262 -0
- data/lib/blather/errors/stream_error.rb +253 -0
- data/lib/blather/errors.rb +48 -0
- data/lib/blather/{core/jid.rb → jid.rb} +15 -26
- data/lib/blather/{core/roster.rb → roster.rb} +22 -0
- data/lib/blather/{core/roster_item.rb → roster_item.rb} +39 -8
- data/lib/blather/stanza/iq/disco.rb +11 -0
- data/lib/blather/stanza/iq/discos/disco_info.rb +86 -0
- data/lib/blather/stanza/iq/discos/disco_items.rb +61 -0
- data/lib/blather/stanza/iq/query.rb +51 -0
- data/lib/blather/stanza/iq/roster.rb +90 -0
- data/lib/blather/stanza/iq.rb +38 -0
- data/lib/blather/stanza/message.rb +58 -0
- data/lib/blather/stanza/presence/status.rb +78 -0
- data/lib/blather/stanza/presence/subscription.rb +72 -0
- data/lib/blather/stanza/presence.rb +45 -0
- data/lib/blather/stanza.rb +101 -0
- data/lib/blather/stream/client.rb +26 -0
- data/lib/blather/stream/component.rb +34 -0
- data/lib/blather/stream/parser.rb +70 -0
- data/lib/blather/stream/resource.rb +48 -0
- data/lib/blather/stream/sasl.rb +173 -0
- data/lib/blather/stream/session.rb +36 -0
- data/lib/blather/stream/stream_handler.rb +39 -0
- data/lib/blather/stream/tls.rb +33 -0
- data/lib/blather/stream.rb +249 -0
- data/lib/blather/xmpp_node.rb +199 -0
- data/lib/blather.rb +40 -41
- data/spec/blather/core_ext/libxml_spec.rb +58 -0
- data/spec/blather/errors/sasl_error_spec.rb +56 -0
- data/spec/blather/errors/stanza_error_spec.rb +148 -0
- data/spec/blather/errors/stream_error_spec.rb +114 -0
- data/spec/blather/errors_spec.rb +40 -0
- data/spec/blather/{core/jid_spec.rb → jid_spec.rb} +9 -1
- data/spec/blather/{core/roster_item_spec.rb → roster_item_spec.rb} +6 -1
- data/spec/blather/{core/roster_spec.rb → roster_spec.rb} +16 -6
- data/spec/blather/stanza/iq/discos/disco_info_spec.rb +207 -0
- data/spec/blather/stanza/iq/discos/disco_items_spec.rb +136 -0
- data/spec/blather/stanza/iq/query_spec.rb +34 -0
- data/spec/blather/stanza/iq/roster_spec.rb +123 -0
- data/spec/blather/stanza/iq_spec.rb +40 -0
- data/spec/blather/stanza/message_spec.rb +52 -0
- data/spec/blather/stanza/presence/status_spec.rb +102 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +85 -0
- data/spec/blather/stanza/presence_spec.rb +53 -0
- data/spec/blather/{core/stanza_spec.rb → stanza_spec.rb} +14 -2
- data/spec/blather/stream/client_spec.rb +787 -0
- data/spec/blather/stream/component_spec.rb +86 -0
- data/spec/blather/{core/xmpp_node_spec.rb → xmpp_node_spec.rb} +76 -23
- data/spec/build_safe.rb +20 -0
- data/spec/spec_helper.rb +7 -17
- metadata +79 -59
- data/CHANGELOG +0 -1
- data/blather.gemspec +0 -73
- data/lib/blather/callback.rb +0 -24
- data/lib/blather/core/errors.rb +0 -24
- data/lib/blather/core/stanza.rb +0 -90
- data/lib/blather/core/stream.rb +0 -179
- data/lib/blather/core/xmpp_node.rb +0 -95
- data/lib/blather/extensions/last_activity.rb +0 -57
- data/lib/blather/extensions/version.rb +0 -85
- data/spec/blather/core/stream_spec.rb +0 -263
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,3 +1,103 @@
|
|
1
1
|
= Blather
|
2
2
|
|
3
3
|
An evented XMPP library
|
4
|
+
|
5
|
+
== Features
|
6
|
+
|
7
|
+
* evented architecture
|
8
|
+
* uses libxml
|
9
|
+
* simplified starting point
|
10
|
+
|
11
|
+
== Project Pages
|
12
|
+
|
13
|
+
GitHub:: https://github.com/sprsquish/blather
|
14
|
+
|
15
|
+
RubyForge:: http://rubyforge.org/projects/squishtech/
|
16
|
+
|
17
|
+
== Author
|
18
|
+
|
19
|
+
Jeff Smick <sprsquish@gmail.com>
|
20
|
+
|
21
|
+
= Usage
|
22
|
+
|
23
|
+
== Installation
|
24
|
+
|
25
|
+
sudo gem install blather
|
26
|
+
|
27
|
+
== Example
|
28
|
+
|
29
|
+
See the /examples directory for more advanced examples.
|
30
|
+
|
31
|
+
This will auto-accept any subscription requests and echo back any chat messages.
|
32
|
+
|
33
|
+
require 'rubygems'
|
34
|
+
require 'blather/client'
|
35
|
+
|
36
|
+
setup 'echo@jabber.local', 'echo'
|
37
|
+
|
38
|
+
# Auto approve subscription requests
|
39
|
+
subscription :request? do |s|
|
40
|
+
write s.approve!
|
41
|
+
end
|
42
|
+
|
43
|
+
# Echo back what was said
|
44
|
+
message :chat?, :body do |m|
|
45
|
+
write m.reply
|
46
|
+
end
|
47
|
+
|
48
|
+
== Handlers
|
49
|
+
|
50
|
+
Setup handlers by calling their names as methods.
|
51
|
+
|
52
|
+
# Will only be called for messages where #chat? responds positively
|
53
|
+
# and #body == 'exit'
|
54
|
+
message :chat?, :body => 'exit'
|
55
|
+
|
56
|
+
=== Handler Guards
|
57
|
+
|
58
|
+
Guards act like AND statements. Each condition must be met if the handler is to be used.
|
59
|
+
|
60
|
+
# Equivalent to saying (stanza.chat? && stanza.body)
|
61
|
+
message :chat?, :body
|
62
|
+
|
63
|
+
There are 5 different types of guards:
|
64
|
+
|
65
|
+
# Symbol
|
66
|
+
# Checks for a non-false reply to calling the symbol on the stanza
|
67
|
+
# Equivalent to stanza.chat?
|
68
|
+
message :chat?
|
69
|
+
|
70
|
+
# Hash with value (:body => 'exit')
|
71
|
+
# Calls the key on the stanza and checks for equality
|
72
|
+
# Equivalent to stanza.body == 'exit'
|
73
|
+
message :body => 'exit'
|
74
|
+
|
75
|
+
# Hash with regular expression (:body => /exit/)
|
76
|
+
# Calls the key on the stanza and checks for a match
|
77
|
+
# Equivalent to stanza.body.match /exit/
|
78
|
+
message :body => /exit/
|
79
|
+
|
80
|
+
# Proc
|
81
|
+
# Calls the proc passing in the stanza
|
82
|
+
# Checks that the ID is modulo 3
|
83
|
+
message proc { |m| m.id % 3 == 0 }
|
84
|
+
|
85
|
+
# Array
|
86
|
+
# Use arrays with the previous types effectively turns the guard into
|
87
|
+
# an OR statement.
|
88
|
+
# Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
|
89
|
+
message [{:body => 'foo'}, {:body => 'baz'}]
|
90
|
+
|
91
|
+
= TODO
|
92
|
+
|
93
|
+
* Cleanup API
|
94
|
+
* Add lambda callback ability to Iq stanzas
|
95
|
+
* Better Documentation
|
96
|
+
* Service Discovery (XEP-0030: http://xmpp.org/extensions/xep-0030.html)
|
97
|
+
* PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
|
98
|
+
* More examples (Re-write XMPP4R examples into Blather)
|
99
|
+
|
100
|
+
= License
|
101
|
+
|
102
|
+
Please see LICENSE
|
103
|
+
The LibXML-Ruby license can be found in its directory
|
data/Rakefile
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = 'blather'
|
8
|
+
gem.summary = 'An evented XMPP library written on EventMachine and libxml-ruby'
|
9
|
+
|
10
|
+
gem.email = 'sprsquish@gmail.com'
|
11
|
+
gem.homepage = 'http://github.com/sprsquish/blather'
|
12
|
+
gem.authors = ['Jeff Smick']
|
13
|
+
|
14
|
+
gem.rubyforge_project = 'squishtech'
|
15
|
+
|
16
|
+
gem.extensions = ['Rakefile']
|
17
|
+
|
18
|
+
gem.add_dependency 'eventmachine', '>= 0.12.6'
|
19
|
+
gem.add_dependency 'libxml-ruby', '>= 1.1.3'
|
20
|
+
|
21
|
+
gem.files = FileList['examples/**/*', 'lib/**/*', 'ext/*'].to_a
|
22
|
+
|
23
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
24
|
+
end
|
25
|
+
rescue LoadError
|
26
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |test|
|
31
|
+
test.libs << 'lib' << 'spec'
|
32
|
+
test.pattern = 'spec/**/*_spec.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'rcov/rcovtask'
|
38
|
+
Rcov::RcovTask.new do |test|
|
39
|
+
test.libs << 'spec'
|
40
|
+
test.pattern = 'spec/**/*_spec.rb'
|
41
|
+
test.rcov_opts += ['--exclude \/Library\/Ruby\/Gems,spec\/', '--xrefs']
|
42
|
+
test.verbose = true
|
43
|
+
end
|
44
|
+
rescue LoadError
|
45
|
+
task :rcov do
|
46
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
begin
|
52
|
+
require 'hanna/rdoctask'
|
53
|
+
|
54
|
+
Rake::RDocTask.new do |rdoc|
|
55
|
+
if File.exist?('VERSION.yml')
|
56
|
+
config = YAML.load(File.read('VERSION.yml'))
|
57
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
58
|
+
else
|
59
|
+
version = ""
|
60
|
+
end
|
61
|
+
|
62
|
+
rdoc.rdoc_dir = 'rdoc'
|
63
|
+
rdoc.title = "blather #{version}"
|
64
|
+
rdoc.rdoc_files.include('README*')
|
65
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
66
|
+
rdoc.options += %w[-S -T hanna --main README.rdoc --exclude autotest --exclude vendor]
|
67
|
+
end
|
68
|
+
rescue LoadError
|
69
|
+
task :rdoc do
|
70
|
+
abort "Hanna is not available. In order to use the Hanna, you must: sudo gem install mislav-hanna"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
MAKE = ENV['MAKE'] || (RUBY_PLATFORM =~ /mswin/ ? 'nmake' : 'make')
|
75
|
+
|
76
|
+
namespace :ext do
|
77
|
+
ext_sources = FileList['ext/*.{rb,c}']
|
78
|
+
|
79
|
+
desc 'Compile the makefile'
|
80
|
+
file 'ext/Makefile' => ext_sources do
|
81
|
+
chdir('ext') { ruby 'extconf.rb' }
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "make extension"
|
85
|
+
task :make => ext_sources + ['ext/Makefile'] do
|
86
|
+
chdir('ext') { sh MAKE }
|
87
|
+
end
|
88
|
+
|
89
|
+
desc 'Build push parser'
|
90
|
+
task :build => :make
|
91
|
+
|
92
|
+
desc 'Clean extensions'
|
93
|
+
task :clean do
|
94
|
+
chdir 'ext' do
|
95
|
+
sh "rm -f Makefile"
|
96
|
+
sh "rm -f *.{o,so,bundle,log}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# If running under rubygems...
|
102
|
+
__DIR__ ||= File.expand_path(File.dirname(__FILE__))
|
103
|
+
if Gem.path.any? {|path| %r(^#{Regexp.escape path}) =~ __DIR__}
|
104
|
+
task :default => :gem_build
|
105
|
+
else
|
106
|
+
task :default => ['ext:build', :test]
|
107
|
+
end
|
108
|
+
|
109
|
+
desc ":default build when running under rubygems."
|
110
|
+
task :gem_build => 'ext:build'
|
data/examples/echo.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'blather/client'
|
4
|
+
|
5
|
+
when_ready { puts "Connected ! send messages to #{jid.stripped}." }
|
6
|
+
|
7
|
+
subscription :request? do |s|
|
8
|
+
write s.approve!
|
9
|
+
end
|
10
|
+
|
11
|
+
message :chat?, :body => 'exit' do |m|
|
12
|
+
say m.from, 'Exiting ...'
|
13
|
+
shutdown
|
14
|
+
end
|
15
|
+
|
16
|
+
message :chat?, :body do |m|
|
17
|
+
say m.from, "You sent: #{m.body}"
|
18
|
+
end
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
flags = []
|
4
|
+
|
5
|
+
case RUBY_PLATFORM.split('-',2)[1]
|
6
|
+
when 'mswin32', 'mingw32', 'bccwin32'
|
7
|
+
unless have_header('windows.h') and
|
8
|
+
have_header('winsock.h') and
|
9
|
+
have_library('kernel32') and
|
10
|
+
have_library('rpcrt4') and
|
11
|
+
have_library('gdi32')
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
flags << "-D OS_WIN32"
|
16
|
+
flags << '-D BUILD_FOR_RUBY'
|
17
|
+
flags << "-EHs"
|
18
|
+
flags << "-GR"
|
19
|
+
|
20
|
+
dir_config('xml2')
|
21
|
+
exit unless have_library('xml2') && have_header('libxml/parser.h')
|
22
|
+
|
23
|
+
when /solaris/
|
24
|
+
unless have_library('pthread') and
|
25
|
+
have_library('nsl') and
|
26
|
+
have_library('socket')
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
flags << '-D OS_UNIX'
|
31
|
+
flags << '-D OS_SOLARIS8'
|
32
|
+
flags << '-D BUILD_FOR_RUBY'
|
33
|
+
|
34
|
+
dir_config('xml2')
|
35
|
+
exit unless have_library('xml2') && find_header('libxml/parser.h', '/usr/include/libxml2')
|
36
|
+
|
37
|
+
# on Unix we need a g++ link, not gcc.
|
38
|
+
#CONFIG['LDSHARED'] = "$(CXX) -shared"
|
39
|
+
|
40
|
+
when /darwin/
|
41
|
+
flags << '-DOS_UNIX'
|
42
|
+
flags << '-DBUILD_FOR_RUBY'
|
43
|
+
|
44
|
+
dir_config('xml2')
|
45
|
+
exit unless have_library('xml2') && find_header('libxml/parser.h', '/usr/include/libxml2')
|
46
|
+
# on Unix we need a g++ link, not gcc.
|
47
|
+
#CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
|
48
|
+
|
49
|
+
else
|
50
|
+
unless have_library('pthread')
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
|
54
|
+
flags << '-DOS_UNIX'
|
55
|
+
flags << '-DBUILD_FOR_RUBY'
|
56
|
+
|
57
|
+
dir_config('xml2')
|
58
|
+
exit unless have_library('xml2') && find_header('libxml/parser.h', '/usr/include/libxml2')
|
59
|
+
# on Unix we need a g++ link, not gcc.
|
60
|
+
#CONFIG['LDSHARED'] = "$(CXX) -shared"
|
61
|
+
end
|
62
|
+
|
63
|
+
$CFLAGS += ' ' + flags.join(' ')
|
64
|
+
|
65
|
+
create_makefile "push_parser"
|
data/ext/push_parser.c
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
/*
|
2
|
+
* Most of this was ripped from libxml-ruby's SAX handler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <libxml/parser.h>
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
xmlSAXHandler saxHandler;
|
9
|
+
|
10
|
+
static VALUE
|
11
|
+
push_parser_raise_error (
|
12
|
+
xmlErrorPtr error)
|
13
|
+
{
|
14
|
+
rb_raise(rb_eStandardError, "%s", rb_str_new2((const char*)error->message));
|
15
|
+
return Qnil;
|
16
|
+
}
|
17
|
+
|
18
|
+
static VALUE
|
19
|
+
push_parser_initialize (
|
20
|
+
VALUE self,
|
21
|
+
VALUE handler)
|
22
|
+
{
|
23
|
+
xmlParserCtxtPtr ctxt;
|
24
|
+
ctxt = xmlCreatePushParserCtxt(&saxHandler, (void *)handler, NULL, 0, NULL);
|
25
|
+
|
26
|
+
if (!ctxt)
|
27
|
+
return push_parser_raise_error(&xmlLastError);
|
28
|
+
|
29
|
+
ctxt->sax2 = 1;
|
30
|
+
|
31
|
+
rb_iv_set(self, "@__libxml_push_parser", Data_Wrap_Struct(rb_cData, 0, xmlFreeParserCtxt, ctxt));
|
32
|
+
|
33
|
+
return self;
|
34
|
+
}
|
35
|
+
|
36
|
+
static VALUE
|
37
|
+
push_parser_close (
|
38
|
+
VALUE self)
|
39
|
+
{
|
40
|
+
xmlParserCtxtPtr ctxt;
|
41
|
+
Data_Get_Struct(rb_iv_get(self, "@__libxml_push_parser"), xmlParserCtxt, ctxt);
|
42
|
+
|
43
|
+
if (xmlParseChunk(ctxt, "", 0, 1)) {
|
44
|
+
return push_parser_raise_error(&xmlLastError);
|
45
|
+
}
|
46
|
+
else {
|
47
|
+
return Qtrue;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
static VALUE
|
52
|
+
push_parser_receive (
|
53
|
+
VALUE self,
|
54
|
+
VALUE chunk)
|
55
|
+
{
|
56
|
+
const char *data = StringValuePtr(chunk);
|
57
|
+
int length = RSTRING_LEN(chunk);
|
58
|
+
|
59
|
+
xmlParserCtxtPtr ctxt;
|
60
|
+
Data_Get_Struct(rb_iv_get(self, "@__libxml_push_parser"), xmlParserCtxt, ctxt);
|
61
|
+
|
62
|
+
// Chunk through in 4KB chunks so as not to overwhelm the buffers
|
63
|
+
int i;
|
64
|
+
int chunkSize = length < 4096 ? length : 4096;
|
65
|
+
for (i = 0; i < length; i += chunkSize) {
|
66
|
+
xmlParseChunk(ctxt, data+i, chunkSize, 0);
|
67
|
+
}
|
68
|
+
if ((i -= length) > 0)
|
69
|
+
xmlParseChunk(ctxt, data+(length-i), i, 0);
|
70
|
+
|
71
|
+
return self;
|
72
|
+
}
|
73
|
+
|
74
|
+
/*********
|
75
|
+
CALLBACKS
|
76
|
+
**********/
|
77
|
+
static void
|
78
|
+
push_parser_start_document_callback (
|
79
|
+
void *ctx)
|
80
|
+
{
|
81
|
+
VALUE handler = (VALUE) ctx;
|
82
|
+
if (handler != Qnil)
|
83
|
+
rb_funcall (handler, rb_intern("on_start_document"), 0);
|
84
|
+
}
|
85
|
+
|
86
|
+
static void
|
87
|
+
push_parser_end_document_callback (
|
88
|
+
void *ctx)
|
89
|
+
{
|
90
|
+
VALUE handler = (VALUE) ctx;
|
91
|
+
if (handler != Qnil)
|
92
|
+
rb_funcall (handler, rb_intern("on_end_document"), 0);
|
93
|
+
}
|
94
|
+
|
95
|
+
static void
|
96
|
+
push_parser_start_element_ns_callback (
|
97
|
+
void * ctx,
|
98
|
+
const xmlChar * localname,
|
99
|
+
const xmlChar * prefix,
|
100
|
+
const xmlChar * URI,
|
101
|
+
int nb_namespaces,
|
102
|
+
const xmlChar ** namespaces,
|
103
|
+
int nb_attributes,
|
104
|
+
int nb_defaulted,
|
105
|
+
const xmlChar ** attributes)
|
106
|
+
{
|
107
|
+
VALUE handler = (VALUE) ctx;
|
108
|
+
if (handler == Qnil)
|
109
|
+
return;
|
110
|
+
|
111
|
+
VALUE attrHash = rb_hash_new();
|
112
|
+
VALUE nsHash = rb_hash_new();
|
113
|
+
|
114
|
+
if (attributes)
|
115
|
+
{
|
116
|
+
/* Each attribute is an array of [localname, prefix, URI, value, end] */
|
117
|
+
int i;
|
118
|
+
for (i = 0; i < nb_attributes * 5; i += 5)
|
119
|
+
{
|
120
|
+
rb_hash_aset( attrHash,
|
121
|
+
rb_str_new2((const char*)attributes[i+0]),
|
122
|
+
rb_str_new((const char*)attributes[i+3], attributes[i+4] - attributes[i+3]));
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
if (namespaces)
|
127
|
+
{
|
128
|
+
int i;
|
129
|
+
for (i = 0; i < nb_namespaces * 2; i += 2)
|
130
|
+
{
|
131
|
+
rb_hash_aset( nsHash,
|
132
|
+
namespaces[i+0] ? rb_str_new2((const char*)namespaces[i+0]) : Qnil,
|
133
|
+
namespaces[i+1] ? rb_str_new2((const char*)namespaces[i+1]) : Qnil);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
rb_funcall(handler, rb_intern("on_start_element_ns"), 5,
|
138
|
+
rb_str_new2((const char*)localname),
|
139
|
+
attrHash,
|
140
|
+
prefix ? rb_str_new2((const char*)prefix) : Qnil,
|
141
|
+
URI ? rb_str_new2((const char*)URI) : Qnil,
|
142
|
+
nsHash);
|
143
|
+
}
|
144
|
+
|
145
|
+
static void
|
146
|
+
push_parser_end_element_ns_callback (
|
147
|
+
void * ctx,
|
148
|
+
const xmlChar * localname,
|
149
|
+
const xmlChar * prefix,
|
150
|
+
const xmlChar * URI)
|
151
|
+
{
|
152
|
+
VALUE handler = (VALUE) ctx;
|
153
|
+
if (handler == Qnil)
|
154
|
+
return;
|
155
|
+
|
156
|
+
rb_funcall(handler, rb_intern("on_end_element_ns"), 3,
|
157
|
+
rb_str_new2((const char*)localname),
|
158
|
+
prefix ? rb_str_new2((const char*)prefix) : Qnil,
|
159
|
+
URI ? rb_str_new2((const char*)URI) : Qnil);
|
160
|
+
}
|
161
|
+
|
162
|
+
|
163
|
+
static void
|
164
|
+
push_parser_characters_callback (
|
165
|
+
void *ctx,
|
166
|
+
const char *chars,
|
167
|
+
int len)
|
168
|
+
{
|
169
|
+
VALUE handler = (VALUE) ctx;
|
170
|
+
if (handler != Qnil)
|
171
|
+
rb_funcall (handler, rb_intern("on_characters"), 1, rb_str_new(chars, len));
|
172
|
+
}
|
173
|
+
|
174
|
+
static void
|
175
|
+
push_parser_structured_error_callback (
|
176
|
+
void *ctx,
|
177
|
+
xmlErrorPtr error)
|
178
|
+
{
|
179
|
+
VALUE handler = (VALUE) ctx;
|
180
|
+
if (handler != Qnil)
|
181
|
+
rb_funcall (handler, rb_intern("on_error"), 1, rb_str_new2((const char*)error->message));
|
182
|
+
}
|
183
|
+
|
184
|
+
xmlSAXHandler saxHandler = {
|
185
|
+
0, //internalSubset
|
186
|
+
0, //isStandalone
|
187
|
+
0, //hasInternalSubset
|
188
|
+
0, //hasExternalSubset
|
189
|
+
0, //resolveEntity
|
190
|
+
0, //getEntity
|
191
|
+
0, //entityDecl
|
192
|
+
0, //notationDecl
|
193
|
+
0, //attributeDecl
|
194
|
+
0, //elementDecl
|
195
|
+
0, //unparsedEntityDecl
|
196
|
+
0, //setDocumentLocator
|
197
|
+
(startDocumentSAXFunc) push_parser_start_document_callback,
|
198
|
+
(endDocumentSAXFunc) push_parser_end_document_callback,
|
199
|
+
0, //startElement
|
200
|
+
0, //endElement
|
201
|
+
0, //reference
|
202
|
+
(charactersSAXFunc) push_parser_characters_callback,
|
203
|
+
0, //ignorableWhitespace
|
204
|
+
0, //processingInstruction
|
205
|
+
0, //comment
|
206
|
+
0, //warning
|
207
|
+
(errorSAXFunc) push_parser_structured_error_callback,
|
208
|
+
0, //fatalError
|
209
|
+
0, //getParameterEntity
|
210
|
+
0, //cdataBlock
|
211
|
+
0, //externalSubset
|
212
|
+
XML_SAX2_MAGIC,
|
213
|
+
0, //_private
|
214
|
+
(startElementNsSAX2Func) push_parser_start_element_ns_callback,
|
215
|
+
(endElementNsSAX2Func) push_parser_end_element_ns_callback,
|
216
|
+
(xmlStructuredErrorFunc) push_parser_structured_error_callback
|
217
|
+
};
|
218
|
+
|
219
|
+
void
|
220
|
+
Init_push_parser()
|
221
|
+
{
|
222
|
+
/* SaxPushParser */
|
223
|
+
VALUE mLibXML = rb_define_module("LibXML");
|
224
|
+
VALUE mXML = rb_define_module_under(mLibXML, "XML");
|
225
|
+
VALUE cXMLSaxPushParser = rb_define_class_under(mXML, "SaxPushParser", rb_cObject);
|
226
|
+
|
227
|
+
/* Instance Methods */
|
228
|
+
rb_define_method(cXMLSaxPushParser, "initialize", push_parser_initialize, 1);
|
229
|
+
rb_define_method(cXMLSaxPushParser, "receive", push_parser_receive, 1);
|
230
|
+
rb_define_method(cXMLSaxPushParser, "close", push_parser_close, 0);
|
231
|
+
}
|