skates 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +113 -0
  3. data/Rakefile +143 -0
  4. data/bin/skates +6 -0
  5. data/lib/skates.rb +108 -0
  6. data/lib/skates/base/controller.rb +116 -0
  7. data/lib/skates/base/stanza.rb +23 -0
  8. data/lib/skates/base/view.rb +58 -0
  9. data/lib/skates/client_connection.rb +210 -0
  10. data/lib/skates/component_connection.rb +87 -0
  11. data/lib/skates/generator.rb +139 -0
  12. data/lib/skates/router.rb +101 -0
  13. data/lib/skates/router/dsl.rb +61 -0
  14. data/lib/skates/runner.rb +137 -0
  15. data/lib/skates/xmpp_connection.rb +172 -0
  16. data/lib/skates/xmpp_parser.rb +117 -0
  17. data/lib/skates/xpath_helper.rb +13 -0
  18. data/spec/bin/babylon_spec.rb +0 -0
  19. data/spec/em_mock.rb +42 -0
  20. data/spec/lib/babylon/base/controller_spec.rb +205 -0
  21. data/spec/lib/babylon/base/stanza_spec.rb +15 -0
  22. data/spec/lib/babylon/base/view_spec.rb +92 -0
  23. data/spec/lib/babylon/client_connection_spec.rb +304 -0
  24. data/spec/lib/babylon/component_connection_spec.rb +135 -0
  25. data/spec/lib/babylon/generator_spec.rb +10 -0
  26. data/spec/lib/babylon/router/dsl_spec.rb +72 -0
  27. data/spec/lib/babylon/router_spec.rb +189 -0
  28. data/spec/lib/babylon/runner_spec.rb +213 -0
  29. data/spec/lib/babylon/xmpp_connection_spec.rb +197 -0
  30. data/spec/lib/babylon/xmpp_parser_spec.rb +275 -0
  31. data/spec/lib/babylon/xpath_helper_spec.rb +25 -0
  32. data/spec/spec_helper.rb +34 -0
  33. data/templates/skates/app/controllers/controller.rb +7 -0
  34. data/templates/skates/app/stanzas/stanza.rb +6 -0
  35. data/templates/skates/app/views/view.rb +6 -0
  36. data/templates/skates/config/boot.rb +16 -0
  37. data/templates/skates/config/config.yaml +24 -0
  38. data/templates/skates/config/dependencies.rb +1 -0
  39. data/templates/skates/config/routes.rb +22 -0
  40. data/templates/skates/log/development.log +0 -0
  41. data/templates/skates/log/production.log +0 -0
  42. data/templates/skates/log/test.log +0 -0
  43. data/templates/skates/script/component +36 -0
  44. data/templates/skates/tmp/pids/README +2 -0
  45. data/test/skates_test.rb +7 -0
  46. data/test/test_helper.rb +10 -0
  47. metadata +160 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 julien
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,113 @@
1
+ = Skates
2
+
3
+ == DESCRIPTION:
4
+
5
+ Skates is a framework to build XMPP Applications in Ruby. The framework uses EventMachine to handle network connections.
6
+
7
+ This framework can use both an XMPP Component (XEP-0114) and an XMPP Client (and XMPP Servers should come soon). However, we strongly discourage any production application using a regular client.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ Please link "report/request here.":http://github.com/julien51/skates/issues
12
+
13
+ The current version is a good candidate for version 0.1. We will probably not add any important features before that release, but we need some help with the tests and documentation.
14
+
15
+ == ROADMAP :
16
+
17
+ - Implement the ServerConnection for S2S
18
+ - Implement templates for disco-info... and common XEPs
19
+ - Delete route priorities? And rely on the order only? (As Rails does)
20
+ - Review doc
21
+ - Write tests
22
+ - Evangelize!
23
+
24
+ You can help with at least one of these points, don't turn your back on Skates!
25
+
26
+ == DOCUMENTATION :
27
+
28
+ You can find it on our "Rubyforge page":http://skates.rubyforge.org/
29
+ Feel free to fork the "github":http://github.com/julien51/skates/tree/master repo and add some documentation if you think anything is missing.
30
+
31
+ __You can't be a bad coder, a bad tester and a bad documenter at the same time ;)__
32
+
33
+ == SYNOPSIS :
34
+
35
+ You can build applications directly with Skates, or you can use the Skates::ClientConnection and Skates::ComponentConnection to create simple apps, but you will then have to handle stanza routing and creation yourself. You can also use these classes in external gems.
36
+
37
+ === To create an Application with Skates:
38
+
39
+ 1. Install the gem
40
+ 2. The app contains a generator that will "build" a scaffold for your application.
41
+
42
+ $> skates application __myapp__
43
+
44
+ 3. Use the generator or write your own controllers :
45
+
46
+ $> skates controller __messages__ __echo__:__10__:__//stream:message[@type='chat']/body__,__subscribed__:__0__:__//stream:presence[@type='subscribe']__
47
+
48
+ This will generate a __MessagesController__ class with 2 methods : __echo__ and __subscribed__.
49
+ - "echo" will be called when the component receives message stanzas of type 'chat',
50
+ - "subscribed" will be called for presence stanzas of type 'subscribe'.
51
+ 10 and 0 are the priority : useful when a stanza matches 2 XPath.
52
+
53
+ Each of these actions will be called with stanza objects. You have to define your own objects in __stanzas/echo.rb__ and __stanzas/subscribed.rb__
54
+ By implementing them, you can choose which elements and attributes you want to have access to. These attributes will be populated upon instantiation of the Stanza objects.
55
+
56
+ This will also generate 2 'views' used to build your responses stanzas.
57
+
58
+ And finally, this will write 2 routes in the config/routes.rb
59
+
60
+ 4. Customize your controllers, stanzas and views!
61
+
62
+ 5. Make sure that the XMPP settings are correct in config/config.yaml.
63
+
64
+ 6. And finally start the component :
65
+
66
+ script/component
67
+
68
+ 7. We running in production, you may run the script/component too, but with something like runit to deamonize the process.
69
+
70
+ === To use the Connection Classes only (Client or Component), you can just call the following :
71
+
72
+ Skates::ClientConnection.connect(params, handler)
73
+ or,
74
+ Skates::ComponentConnection.connect(params, handler)
75
+
76
+ where params is a hash for all the necessary information to connect, and handler is an object that will receive the callbacks. Right now 3 callbacks are supported:
77
+
78
+ on_connected(connection), on_disconnected and on_stanza(stanza)
79
+
80
+ == ADDITIONAL INFORMATION :
81
+
82
+ Feel free to pull, branch, improve and commit the {code|specs|tests|docs} : we will merge it if it's a step ahead!
83
+
84
+ Skates's edge versions are located at Github : http://github.com/julien51/skates/tree/master
85
+
86
+ == REQUIREMENTS :
87
+
88
+ Gems : Eventmachine, nokogiri (please, use build from the guthub repo, since 1.2.3 is not supported by Skates), YAML, log4r, sax-machine, templater
89
+
90
+ == LICENSE:
91
+
92
+ (The MIT License)
93
+
94
+ Copyright (c) 2009 Julien Genestoux http://notifixio.us
95
+
96
+ Permission is hereby granted, free of charge, to any person obtaining
97
+ a copy of this software and associated documentation files (the
98
+ 'Software'), to deal in the Software without restriction, including
99
+ without limitation the rights to use, copy, modify, merge, publish,
100
+ distribute, sublicense, and/or sell copies of the Software, and to
101
+ permit persons to whom the Software is furnished to do so, subject to
102
+ the following conditions:
103
+
104
+ The above copyright notice and this permission notice shall be
105
+ included in all copies or substantial portions of the Software.
106
+
107
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
108
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
109
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
110
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
111
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
112
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
113
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,143 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "skates"
8
+ gem.summary = %Q{Skates is a framework to create EventMachine based XMPP External Components in Ruby.}
9
+ gem.email = "julien.genestoux@gmail.com"
10
+ gem.homepage = "http://github.com/julien51/skates"
11
+ gem.authors = ["julien Genestoux"]
12
+
13
+ gem.add_dependency('eventmachine', ">= 0.12.10")
14
+ gem.add_dependency('log4r')
15
+ gem.add_dependency('nokogiri', ">= 1.4.0")
16
+ gem.add_dependency('julien51-sax-machine', ">= 0.0.20")
17
+ gem.add_dependency('templater')
18
+ gem.requirements = ["eventmachine", "yaml", "fileutils", "log4r", "nokogiri", "julien51-sax-machine", "templater", "optparse", "digest/sha1", "base64", "resolv", "activesupport"]
19
+ gem.executables = "skates"
20
+ gem.files = [ "bin/skates",
21
+ "lib/skates.rb",
22
+ "lib/skates/base/controller.rb",
23
+ "lib/skates/base/view.rb",
24
+ "lib/skates/base/stanza.rb",
25
+ "lib/skates/client_connection.rb",
26
+ "lib/skates/component_connection.rb",
27
+ "lib/skates/router/dsl.rb",
28
+ "lib/skates/router.rb",
29
+ "lib/skates/runner.rb",
30
+ "lib/skates/generator.rb",
31
+ "lib/skates/xmpp_connection.rb",
32
+ "lib/skates/xmpp_parser.rb",
33
+ "lib/skates/xpath_helper.rb",
34
+ "LICENSE",
35
+ "Rakefile",
36
+ "README.rdoc",
37
+ "templates/skates/app/controllers/controller.rb",
38
+ "templates/skates/app/views/view.rb",
39
+ "templates/skates/app/stanzas/stanza.rb",
40
+ "templates/skates/config/boot.rb",
41
+ "templates/skates/config/config.yaml",
42
+ "templates/skates/config/dependencies.rb",
43
+ "templates/skates/config/routes.rb",
44
+ "templates/skates/script/component",
45
+ "templates/skates/log/test.log",
46
+ "templates/skates/log/development.log",
47
+ "templates/skates/log/production.log",
48
+ "templates/skates/tmp/pids/README"
49
+ ]
50
+ gem.rubyforge_project = 'skates'
51
+ end
52
+ rescue LoadError
53
+ puts "Jeweler not available. Install it with: sudo gem jeweler"
54
+ end
55
+
56
+ require 'rake/rdoctask'
57
+ Rake::RDocTask.new do |rdoc|
58
+ rdoc.rdoc_dir = 'rdoc'
59
+ rdoc.title = 'Skates : a framework to create EventMachine based XMPP External Components in Ruby.'
60
+ rdoc.rdoc_files.include('README*')
61
+ rdoc.rdoc_files.include('lib/**/*.rb')
62
+ rdoc.options << '--line-numbers'
63
+ end
64
+
65
+ require 'rake/testtask'
66
+ Rake::TestTask.new(:test) do |test|
67
+ test.libs << 'lib' << 'test'
68
+ test.pattern = 'test/**/*_test.rb'
69
+ test.verbose = false
70
+ end
71
+
72
+ begin
73
+ require 'rcov/rcovtask'
74
+ Rcov::RcovTask.new do |test|
75
+ test.libs << 'test'
76
+ test.pattern = 'test/**/*_test.rb'
77
+ test.verbose = true
78
+ end
79
+ rescue LoadError
80
+ task :rcov do
81
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
82
+ end
83
+ end
84
+
85
+ begin
86
+ require 'spec/rake/spectask'
87
+ desc "Run all Spec"
88
+ Spec::Rake::SpecTask.new('spec') do |spec|
89
+ spec.spec_files = FileList['spec/**/*.rb']
90
+ spec.verbose = true
91
+ spec.warning = false
92
+ spec.rcov = true
93
+ end
94
+ rescue LoadError
95
+ task :spec do
96
+ abort "Rspec is not available. In order to run rspec, you must: sudo gem install rspec"
97
+ end
98
+ end
99
+
100
+ begin
101
+ require 'spec/rake/verify_rcov'
102
+
103
+ RCov::VerifyTask.new(:verify_rcov => 'spec') do |t|
104
+ t.threshold = 100.0
105
+ t.index_html = 'coverage/index.html'
106
+ end
107
+ rescue LoadError
108
+ task :spec do
109
+ abort "Rcov is not available. In order to run rcov, you must: sudo gem install rcov"
110
+ end
111
+ end
112
+
113
+ # These are Rubyforge tasks
114
+ begin
115
+ require 'rake/contrib/sshpublisher'
116
+ namespace :rubyforge do
117
+
118
+ desc "Release gem and RDoc documentation to RubyForge"
119
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
120
+
121
+ namespace :release do
122
+ desc "Publish RDoc to RubyForge."
123
+ task :docs => [:rdoc] do
124
+ config = YAML.load(
125
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
126
+ )
127
+
128
+ host = "#{config['username']}@rubyforge.org"
129
+ remote_dir = "/var/www/gforge-projects/skates"
130
+ local_dir = 'rdoc'
131
+
132
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
133
+ end
134
+ end
135
+ end
136
+ rescue LoadError
137
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
138
+ end
139
+
140
+
141
+ task :install => :build
142
+
143
+ task :default => :test
data/bin/skates ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'skates'
5
+
6
+ Skates::Generator.run_cli(Dir.pwd, 'skates_app', "0.1", ARGV)
data/lib/skates.rb ADDED
@@ -0,0 +1,108 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'eventmachine'
5
+ require 'log4r'
6
+ require 'activesupport'
7
+ require 'nokogiri'
8
+ require 'yaml'
9
+ require 'fileutils'
10
+ require 'sax-machine'
11
+ require 'digest/sha1'
12
+ require 'base64'
13
+ require 'resolv'
14
+ require 'templater'
15
+ require 'cgi'
16
+
17
+ require 'skates/xmpp_connection'
18
+ require 'skates/xmpp_parser'
19
+ require 'skates/component_connection'
20
+ require 'skates/client_connection'
21
+ require 'skates/router'
22
+ require 'skates/runner'
23
+ require 'skates/generator'
24
+ require 'skates/xpath_helper'
25
+ require 'skates/base/controller'
26
+ require 'skates/base/view'
27
+ require 'skates/base/stanza'
28
+
29
+ # Skates is a XMPP Component Framework based on EventMachine. It uses the Nokogiri GEM, which is a Ruby wrapper for Libxml2.
30
+ # It implements the MVC paradigm.
31
+ # You can create your own application by running :
32
+ # $> skates app_name
33
+ # This will generate some folders and files for your application. Please see README.rdoc for further instructions
34
+
35
+ module Skates
36
+
37
+ def self.environment=(_env)
38
+ @@env = _env
39
+ end
40
+
41
+ def self.environment
42
+ unless self.class_variable_defined?("@@env")
43
+ @@env = "development"
44
+ end
45
+ @@env
46
+ end
47
+
48
+ ##
49
+ # Sets up the router
50
+ def self.router=(router)
51
+ @@router = router
52
+ end
53
+
54
+ ##
55
+ # Retruns the router
56
+ def self.router
57
+ unless self.class_variable_defined?("@@router")
58
+ @@router = nil
59
+ end
60
+ @@router
61
+ end
62
+
63
+ ##
64
+ # Caches the view files to improve performance.
65
+ def self.cache_views
66
+ @@views= {}
67
+ Dir.glob('app/views/*/*').each do |f|
68
+ @@views[f] = File.read(f)
69
+ end
70
+ end
71
+
72
+ def self.views
73
+ unless self.class_variable_defined?("@@views")
74
+ @@views= {}
75
+ end
76
+ @@views
77
+ end
78
+
79
+ ##
80
+ # Returns a shared logger for this component.
81
+ def self.logger
82
+ unless self.class_variable_defined?("@@logger")
83
+ @@logger = Log4r::Logger.new("Skates")
84
+ @@logger.add(Log4r::Outputter.stdout) if Skates.environment == "development"
85
+ end
86
+ @@logger
87
+ end
88
+
89
+ ##
90
+ # Set the configuration for this component.
91
+ def self.config=(conf)
92
+ @@config = conf
93
+ end
94
+
95
+ ##
96
+ # Return the configuration for this component.
97
+ def self.config
98
+ @@config
99
+ end
100
+
101
+ ##
102
+ # Decodes XML special characters.
103
+ def self.decode_xml(str)
104
+ CGI.unescapeHTML(str)
105
+ end
106
+
107
+ end
108
+
@@ -0,0 +1,116 @@
1
+ module Skates
2
+ module Base
3
+
4
+ ##
5
+ # Your application's controller should be descendant of this class.
6
+ class Controller
7
+
8
+ attr_accessor :stanza, :rendered, :action_name # Stanza received by the controller (Nokogiri::XML::Node)
9
+
10
+ ##
11
+ # Creates a new controller (you should not override this class) and assigns the stanza as well as any other value of the hash to instances named after the keys of the hash.
12
+ def initialize(stanza = nil)
13
+ @stanza = stanza
14
+ @view = nil
15
+ end
16
+
17
+ ##
18
+ # Performs the action and calls back the optional block argument : you should not override this function
19
+ def perform(action)
20
+ @action_name = action
21
+ begin
22
+ self.send(@action_name)
23
+ rescue
24
+ Skates.logger.error {
25
+ "#{$!}:\n#{$!.backtrace.join("\n")}"
26
+ }
27
+ end
28
+ self.render
29
+ end
30
+
31
+ ##
32
+ # Returns the list of variables assigned during the action.
33
+ def assigns
34
+ vars = Hash.new
35
+ instance_variables.each do |var|
36
+ if !["@view", "@action_name", "@block"].include? var
37
+ vars[var[1..-1]] = instance_variable_get(var)
38
+ end
39
+ end
40
+ vars
41
+ end
42
+
43
+ ##
44
+ # Called by default after each action to "build" a XMPP stanza. By default, it will use the /controller_name/action.xml.builder
45
+ # You can use the following options :
46
+ # - :file : render a specific file (can be in a different controller)
47
+ # - :action : render another action of the current controller
48
+ # - :nothing : doesn't render anything
49
+ def render(options = {})
50
+ return if @view and !options[:force] # Avoid double rendering, if we have already attached a view
51
+
52
+ if options == {} # default rendering
53
+ result = render(:file => default_template_name)
54
+ elsif options[:file]
55
+ file = options[:file]
56
+ if file =~ /^\// # Render from view root
57
+ result = render_for_file(File.join("app", "views", "#{file}.xml.builder"))
58
+ else
59
+ result = render_for_file(view_path(file))
60
+ end
61
+ elsif action_name = options[:action]
62
+ result = render(:file => default_template_name(action_name.to_s))
63
+ elsif options[:nothing]
64
+ @view = Skates::Base::View.new()
65
+ end
66
+ end
67
+
68
+ ##
69
+ # Actually evaluates the view
70
+ def evaluate
71
+ @view.evaluate if @view
72
+ end
73
+
74
+ ##
75
+ # Render and evaluate a given view
76
+ def render_and_evaluate(options = {})
77
+ render(options)
78
+ evaluate
79
+ end
80
+
81
+ ##
82
+ # Renders, evaluate and sends
83
+ def render_evaluate_and_send(options)
84
+ response = render_and_evaluate(options)
85
+ Skates.router.connection.send_xml response
86
+ end
87
+
88
+ protected
89
+
90
+ ##
91
+ # Builds the view path.
92
+ def view_path(file_name)
93
+ File.join("app", "views", "#{self.class.name.gsub("Controller","").downcase}", file_name)
94
+ end
95
+
96
+ ##
97
+ # Default template name used to build stanzas
98
+ def default_template_name(action_name = nil)
99
+ "#{action_name || @action_name}.xml.builder"
100
+ end
101
+
102
+ ##
103
+ # Creates the view and "evaluates" it to build the XML for the stanza
104
+ def render_for_file(file)
105
+ Skates.logger.info {
106
+ "RENDERING : #{file}"
107
+ }
108
+ @view = Skates::Base::View.new(file, assigns)
109
+ Skates.logger.info {
110
+ " "
111
+ }
112
+ end
113
+
114
+ end
115
+ end
116
+ end