js-client-bridge 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ == 0.1.0 2009-03-28
2
+
3
+ * Repackaged an earlier version of this gem in a more modern way.
@@ -0,0 +1,21 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/js-client-bridge.rb
6
+ lib/js-client-bridge/responses.rb
7
+ lib/js-client-bridge/responses/ok.rb
8
+ lib/js-client-bridge/responses/validation.rb
9
+ lib/js-client-bridge/responses/error.rb
10
+ lib/js-client-bridge/responses/exception.rb
11
+ lib/js-client-bridge/extensions/datamapper_errors.rb
12
+ script/console
13
+ script/destroy
14
+ script/generate
15
+ spec/ok_responses_spec.rb
16
+ spec/error_responses_spec.rb
17
+ spec/exception_responses_spec.rb
18
+ spec/validation_responses_spec.rb
19
+ spec/spec.opts
20
+ spec/spec_helper.rb
21
+ tasks/rspec.rake
@@ -0,0 +1,186 @@
1
+ = js-client-bridge
2
+
3
+ * https://github.com/luma/js-client-bridge/tree/master
4
+
5
+ == DESCRIPTION:
6
+
7
+ Little library that encapsulates a (particular) standardised way of talking between a service and javascript. Probably not the best way of doing things, but it's been handy in a pinch.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * TODO
12
+
13
+ == SYNOPSIS:
14
+
15
+ === Standard and Custom Fields
16
+ Any fields that begin with a '_' are standard fields that will be used among all the different response types. These fields are quite often required or will have specific set behavior that the client side is expected to follow. Any fields that don't begin with '_' are custom fields and the client side can use them (or not) however they want.
17
+
18
+ === Use of JSON With Padding (JSONP)
19
+ We support JSONP (see [http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/ Here] for an introduction to JSONP). Meaning that, rather than the standard JSON responses below:
20
+
21
+ {
22
+ _status : 'ok',
23
+ _message : 'a status message'
24
+ }
25
+
26
+
27
+ A service may be required to return a response of the form:
28
+
29
+ jsonp_identifier_12321({
30
+ _status : 'ok',
31
+ _message : 'a status message'
32
+ } )
33
+
34
+
35
+ Whether JSONP is used for a response or not is decided by the calling client and services should support either response format.
36
+
37
+
38
+ === Everything's Cool Response
39
+ This is returned when a remote call succeeds, it must include the status of 'ok'. It can optionally include a message, if a message is included it should be displayed to the user.
40
+
41
+
42
+ ==== Required Fields
43
+ [_status] String - This will always be 'ok'.
44
+
45
+
46
+ ==== Optional Fields
47
+ [_message] String - If sent from server-side client side should display it.
48
+
49
+ ==== Example
50
+ {
51
+ _status : 'ok',
52
+ _message : 'a status message'
53
+ }
54
+
55
+
56
+ === A General Error Occurred
57
+ This is returned when a remote call fails with a general error, where in this case general error means we want to display feedback to the user but we want to leave any further action up to the client side. It can optionally include a message, if a message is included it should be displayed to the user.
58
+
59
+
60
+ ==== Required Fields
61
+ [_status] String - This will always be 'error'.
62
+
63
+ ==== Optional Fields
64
+ [_message] String - If sent from server-side client side should display it.
65
+
66
+ ==== Example
67
+ {
68
+ _status : 'error',
69
+ _message : 'asdfasfasd'
70
+ }
71
+
72
+ === An Unexpected Exception Occurred
73
+ This is returned when something explodes on the server side. These errors are assumed to be unhandlable on the client side (due to the absurdly large number of possible errors). The client side should take the error info and display it to the user in a standard format. During development or testing this should include displaying all the information on the screen. What happens in production is an open question.
74
+
75
+
76
+ ==== Required Fields
77
+ [_status] String - This will always be 'error'.
78
+ [_type] String - This will be the fully namespaced name of the exception.
79
+ [_short_type] String - This will be the short, easily readable version of _type.
80
+ [request_uri] String - The uri of the original request that triggered this exception.
81
+ [parameters] Hash - A hash of key/value pairs representing the query string or POSTed data. If there are none, an empty hash ({}) should be used.
82
+
83
+ ==== Optional Fields
84
+ [_message] String - If sent from server-side client side should display it.
85
+
86
+ ==== Example
87
+ {
88
+ _status : "exception",
89
+ _type : "Merb::Controller::Exceptions::InternalServerError",
90
+ _short_type : "InternalServerError",
91
+ request_uri : '/asdf,
92
+ parameters : {name : value, name : value, name : value},
93
+ exceptions : [
94
+ {
95
+ name : 'Twimmy::Exceptions::ServerError',
96
+ message : 'A awful error occured',
97
+ backtrace : [
98
+ "file:line",
99
+ "file:line",
100
+ "file:line",
101
+ "file:line"
102
+ ]
103
+ ]
104
+ }
105
+
106
+ === Validation for the Request Failed
107
+ This response is returned when server side validation of an object failed, it should include enough information to display dynamic validation messages and highlight/animate input fields. It is suggested that to make this work seamlessly there must be some way to map html field ids to attribute names in a way that won't clash. One way that is quite efficient is to use form element ids of the form:
108
+ '''short_object_type-object_id-attribute_name'''
109
+
110
+ Or if the object is not yet created and doesn't have an id:
111
+ '''short_object_type-attribute_name'''
112
+
113
+ For example, if we were calling a remote service to update an Offer with the id of 1, and validation failed on the bid_amount field then the attribute mapping would be:
114
+ '''offer-1-bid_amount'''
115
+
116
+
117
+ ==== Example
118
+ The advantage of this scheme is that dynamic validation UI bits can be applied to a client side form using something like the following (this is pseudo code, it's untested):
119
+
120
+ var response = get_response_from_server_side();
121
+
122
+ jQuery.each(response.validation, function(field_name, errors) {
123
+ var field_id = [response._short_type, response.id, field_name].join('-');
124
+ $('#' + field_id).highlight().shake().addClass('error').after("<strong class='form-error'>" + errors.join(', ') + "</strong>");
125
+ });
126
+
127
+ ==== Required Fields
128
+ [_status] String - This will always be 'exception'.
129
+ [_type] String - This will be the fully namespaced name of the exception.
130
+ [_short_type] String - This will be the short, easily readable version of _type.
131
+ [validation] Has - The keys of the hash are the field name on which the error occured. these should has no spaces. The values are arrays of strings, where each string is an error message.
132
+
133
+
134
+ === Optional Fields
135
+ [_message] String - If sent from server-side client side should display it.
136
+ [id] String - The server side id of the object.
137
+
138
+ === Example
139
+ {
140
+ "_status" => "validation",
141
+ "_type" => "Twimmy::Test::TestDO",
142
+ "_short_type" => "TestDO",
143
+ "_message" => "Sorry, we couldn't save your TestDO",
144
+ "action" => "create",
145
+ "validation" : {
146
+ "body" : ["Body must not be blank"],
147
+ "subject" : ["Subject must not be blank", "Subject must be between 30 and 155 characters long"],
148
+ "id" : ["Id must not be blank"]
149
+ },
150
+ }
151
+
152
+ == REQUIREMENTS:
153
+
154
+ * json gem
155
+ * extlib gem
156
+
157
+ == INSTALL:
158
+ The first line add's github as a source for your local rubygems.
159
+
160
+ sudo gem sources -a http://gems.github.com
161
+ sudo gem install luma-js-client-bridge
162
+
163
+ == LICENSE:
164
+
165
+ (The MIT License)
166
+
167
+ Copyright (c) 2009 Rolly
168
+
169
+ Permission is hereby granted, free of charge, to any person obtaining
170
+ a copy of this software and associated documentation files (the
171
+ 'Software'), to deal in the Software without restriction, including
172
+ without limitation the rights to use, copy, modify, merge, publish,
173
+ distribute, sublicense, and/or sell copies of the Software, and to
174
+ permit persons to whom the Software is furnished to do so, subject to
175
+ the following conditions:
176
+
177
+ The above copyright notice and this permission notice shall be
178
+ included in all copies or substantial portions of the Software.
179
+
180
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
181
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
182
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
183
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
184
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
185
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
186
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ =begin
2
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
3
+ require File.dirname(__FILE__) + '/lib/js-client-bridge'
4
+
5
+ # Generate all the Rake tasks
6
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
7
+ $hoe = Hoe.new('js-client-bridge', JsClientBridge::VERSION) do |p|
8
+ p.developer('Rolly', 'rolly@luma.co.nz')
9
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
10
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
11
+ p.rubyforge_name = p.name # TODO this is default value
12
+ p.extra_deps = [
13
+ # ['activesupport','>= 2.0.2'],
14
+ ['json', '>= 0'],
15
+ ['extlib', '>= 0']
16
+ ]
17
+ p.extra_dev_deps = [
18
+ ['newgem', ">= #{::Newgem::VERSION}"]
19
+ ]
20
+
21
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
22
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
23
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
24
+ p.rsync_args = '-av --delete --ignore-errors'
25
+ end
26
+
27
+ require 'newgem/tasks' # load /tasks/*.rake
28
+ Dir['tasks/**/*.rake'].each { |t| load t }
29
+
30
+ # TODO - want other tests/tasks run by default? Add them to the list
31
+ # task :default => [:spec, :features]
32
+
33
+ desc "Run all examples (or a specific spec with TASK=xxxx)"
34
+ Spec::Rake::SpecTask.new('spec') do |t|
35
+ t.spec_opts = ["-cfs"]
36
+ t.spec_files = begin
37
+ if ENV["TASK"]
38
+ ENV["TASK"].split(',').map { |task| "spec/**/#{task}_spec.rb" }
39
+ else
40
+ FileList['spec/**/*_spec.rb']
41
+ end
42
+ end
43
+ end
44
+
45
+ #desc 'Default: run spec examples'
46
+ #task :default => 'spec'
47
+ =end
48
+ # -*- ruby -*-
49
+
50
+ require 'rubygems'
51
+ require 'hoe'
52
+ require 'fileutils'
53
+ require 'newgem'
54
+ require 'rubigen'
55
+
56
+ #require File.dirname(__FILE__) + '/lib/js-client-bridge'
57
+
58
+ Hoe.spec 'js-client-bridge' do
59
+ developer 'Rolly', 'rolly@luma.co.nz'
60
+
61
+ extra_deps << ['json', '>= 0']
62
+ extra_deps << ['extlib', '>= 0']
63
+
64
+ # extra_dev_deps << ['newgem', ">= #{::Newgem::VERSION}"]
65
+ =begin
66
+ clean_globs |= %w[**/.DS_Store tmp *.log]
67
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
68
+ remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
69
+ rsync_args = '-av --delete --ignore-errors'
70
+ =end
71
+ end
72
+
73
+ # vim: syntax=ruby
74
+
@@ -0,0 +1,14 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module JsClientBridge
5
+ VERSION = '0.1.0'
6
+ end
7
+
8
+ require 'rubygems'
9
+ require 'json'
10
+ require "extlib"
11
+ require 'hoe'
12
+
13
+ require 'js-client-bridge/responses'
14
+ require 'js-client-bridge/extensions/datamapper_errors'
@@ -0,0 +1,43 @@
1
+
2
+ module DataMapper
3
+ module Validate
4
+
5
+ ##
6
+ #
7
+ # Monkey patch of Datamapper to add a nice to_json method that uses our error format
8
+ class ValidationErrors
9
+
10
+ def to_hash
11
+ js = {}
12
+
13
+ errors.each do |list, pair|
14
+ js[list] = pair
15
+ end
16
+
17
+ js
18
+ end
19
+
20
+ end # class ValidationErrors
21
+ end # module Validate
22
+ end # module DataMapper
23
+
24
+ module DataMapper
25
+ module Resource
26
+ def errors_to_hash(message = "Sorry, we couldn't save your #{self.class.to_s.split('::').last}")
27
+
28
+ short_type = self.class.to_s.split('::').last
29
+
30
+ validation = {
31
+ :_status => 'validation',
32
+ :_type => self.class,
33
+ :_short_type => short_type,
34
+ :_message => message,
35
+ :validation => self.errors.to_hash,
36
+ }
37
+
38
+ validation[:id] = self.id.to_s unless new_record?
39
+
40
+ validation
41
+ end
42
+ end # module Resource
43
+ end # module DataMapper
@@ -0,0 +1,47 @@
1
+ require 'cgi'
2
+
3
+ base = File.dirname(__FILE__) / 'responses'
4
+ %w(ok error exception validation).each {|f| require base / f }
5
+
6
+ module JSClientBridge #:nodoc:
7
+ module Responses
8
+ class << self
9
+ include Responses::Ok
10
+ include Responses::Error
11
+ include Responses::Exception
12
+ include Responses::Validation
13
+
14
+ protected
15
+
16
+ def formatting_parameters
17
+ [:jsonp]
18
+ end
19
+
20
+ def respond_with(type, args)
21
+ unless args.blank?
22
+ options = args.last.is_a?(Hash) ? args.pop.dup : {}
23
+ options[:_message] = args.shift.dup if args.first.is_a?(String)
24
+ else
25
+ options = {}
26
+ end
27
+
28
+ # separate out formatting parameters
29
+ formatting = {}
30
+ for para in formatting_parameters
31
+ formatting[para] = options.delete(para) if options.include?(para)
32
+ end
33
+
34
+ [options.merge({ :_status => type.to_s }), formatting]
35
+ end
36
+
37
+ def format_response(response, formatting_options = {})
38
+ # Handle JSONP responses
39
+ if formatting_options[:jsonp].blank?
40
+ response.to_json
41
+ else
42
+ "#{formatting_options[:jsonp]}(#{response.to_json})"
43
+ end
44
+ end
45
+ end
46
+ end # module Responses
47
+ end # module JSClientBridge
@@ -0,0 +1,22 @@
1
+ require 'cgi'
2
+
3
+ module JSClientBridge #:nodoc:
4
+ module Responses #:nodoc:
5
+ module Error
6
+ # Generates a error response. If the first parameter is a string is will be
7
+ # used as the _status options. It will also honour custom optionss as long
8
+ # they don't clash with the standard ones.
9
+ #
10
+ # ==== Parameters
11
+ # message<String>:: An optional message.
12
+ # options<Hash>:: Custom optionss.
13
+ #
14
+ # ==== Returns
15
+ # JSON String::
16
+ def respond_with_error(*args)
17
+ format_response(*respond_with('error', args))
18
+ end
19
+
20
+ end # module Error
21
+ end # module Responses
22
+ end # module JSClientBridge
@@ -0,0 +1,60 @@
1
+ require 'cgi'
2
+
3
+ module JSClientBridge #:nodoc:
4
+ module Responses #:nodoc:
5
+ module Exception
6
+
7
+ def respond_with_exception(*args)
8
+ raise ArgumentError.new("respond_with_exception requires an exception as it's first parameter") if args.blank? || !args.first.is_a?(StandardError)
9
+
10
+ exception = args.shift
11
+ options = args.last.is_a?(Hash) ? args.pop : {}
12
+
13
+ # Ensure we have our required fields
14
+ raise ArgumentError.new("respond_with_exception requires the request_uri option") unless options.include?(:request_uri)
15
+
16
+ # Set some defaults
17
+ options[:parameters] ||= {}
18
+
19
+ # Generate our response hash and add the exceptions parameter
20
+ response, formatting = respond_with('exception', [options])
21
+ response[:exceptions] = [{
22
+ :name => exception.class,
23
+ :short_name => exception.class.to_s.split('::').last,
24
+ :message => CGI.escape(exception.message),
25
+ :backtrace => exception.backtrace
26
+ }]
27
+
28
+ format_response(response, formatting)
29
+ end
30
+
31
+ def respond_with_exceptions(*args)
32
+ raise ArgumentError.new("respond_with_exception requires an array of exceptions as it's first parameter") if args.blank? || !args.first.is_a?(Array)
33
+
34
+ exceptions = args.shift
35
+ options = args.last.is_a?(Hash) ? args.pop : {}
36
+
37
+ # Ensure we have our required fields
38
+ raise ArgumentError.new("respond_with_exception requires the request_uri option") unless options.include?(:request_uri)
39
+
40
+ # Set some defaults
41
+ options[:parameters] ||= {}
42
+
43
+ # Generate our response hash and add the exceptions parameter
44
+ response, formatting = respond_with('exception', [options])
45
+
46
+ response[:exceptions] = exceptions.map do |exception|
47
+ {
48
+ :name => exception.class,
49
+ :short_name => exception.class.to_s.split('::').last,
50
+ :message => CGI.escape(exception.message),
51
+ :backtrace => exception.backtrace
52
+ }
53
+ end
54
+
55
+ format_response(response, formatting)
56
+ end
57
+
58
+ end # module Exception
59
+ end # module Responses
60
+ end # module JSClientBridge
@@ -0,0 +1,21 @@
1
+ require 'cgi'
2
+
3
+ module JSClientBridge #:nodoc:
4
+ module Responses #:nodoc:
5
+ module Ok
6
+ # Generates a 'ok' status response. If the first parameter is a string is will be
7
+ # used as the _status options. It will also honour custom optionss as long
8
+ # they don't clash with the standard ones.
9
+ #
10
+ # ==== Parameters
11
+ # message<String>:: An optional message.
12
+ # options<Hash>:: Custom optionss.
13
+ #
14
+ # ==== Returns
15
+ # JSON String::
16
+ def respond_with_ok(*args)
17
+ format_response(*respond_with('ok', args))
18
+ end
19
+ end # module Ok
20
+ end # module Responses
21
+ end # module JSClientBridge
@@ -0,0 +1,47 @@
1
+ require 'cgi'
2
+
3
+ module JSClientBridge #:nodoc:
4
+ module Responses #:nodoc:
5
+ module Validation
6
+ # Generates a 'ok' status response. If the first parameter is a string is will be
7
+ # used as the _status options. It will also honour custom optionss as long
8
+ # they don't clash with the standard ones.
9
+ #
10
+ # ==== Parameters
11
+ # message<String>:: An optional message.
12
+ # options<Hash>:: Custom optionss.
13
+ #
14
+ # ==== Returns
15
+ # JSON String::
16
+ def respond_with_validation_error(*args)
17
+ if args.blank? || !args.first.respond_to?(:errors_to_hash)
18
+ raise ArgumentError.new("respond_with_validation_error requires an object that responds to errors_to_hash as it's first parameter")
19
+ end
20
+
21
+ obj = args.shift
22
+ options = args.last.is_a?(Hash) ? args.pop : {}
23
+
24
+ # Generate our response hash and add the exceptions parameter
25
+ response = if options.include?(:message)
26
+ options.merge(obj.errors_to_hash(options.delete(:message)))
27
+
28
+ else
29
+ options.merge(obj.errors_to_hash)
30
+ end
31
+
32
+ format_response(response, options)
33
+ end
34
+
35
+ end # module Validation
36
+ end # module Responses
37
+ end # module JSClientBridge
38
+
39
+ =begin
40
+ {
41
+ :_status => 'validation',
42
+ :_type => self.class,
43
+ :_short_type => self.class.to_s.split('::').first,
44
+ :_message => message,
45
+ :validation => self.errors.to_json
46
+ }
47
+ =end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/js-client-bridge.rb'}"
9
+ puts "Loading js-client-bridge gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Error Responses" do
4
+ it "should generate a basic error response" do
5
+ JSClientBridge::Responses.respond_with_error.should == {:_status => 'error'}.to_json
6
+ end
7
+
8
+ it "should generate a error response with a status message" do
9
+ JSClientBridge::Responses.respond_with_error('a message').should == {:_status => 'error', :_message => "a message"}.to_json
10
+ end
11
+
12
+ it "should generate a error response with a status message and additional custom properties" do
13
+ JSClientBridge::Responses.respond_with_error('a message', :blame => 'the user').should == {:_status => 'error', :_message => "a message", :blame => 'the user'}.to_json
14
+ end
15
+
16
+ it "should generate a error response with custom properties but not message" do
17
+ JSClientBridge::Responses.respond_with_error(:blame => 'the user').should == {:_status => 'error', :blame => 'the user'}.to_json
18
+ end
19
+
20
+ it "should generate a basic error response using JSONP" do
21
+ JSClientBridge::Responses.respond_with_error('a message', :jsonp => 'jsonp1').should == "jsonp1(#{{:_status => 'error', :_message => "a message"}.to_json})"
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+
4
+
5
+ class TestException < StandardError; end
6
+
7
+ describe "Exception Responses" do
8
+
9
+ it "should generate an exception response" do
10
+ exception = TestException.new('An exception')
11
+
12
+ ex = JSON.parse(JSClientBridge::Responses.respond_with_exception(exception, :request_uri => '/', :parameters => {:param1 => 'value1'}))
13
+
14
+ ex['_status'].should == 'exception'
15
+ ex['request_uri'].should == '/'
16
+ ex['parameters'].should == {'param1' => 'value1'}
17
+ ex['exceptions'].length.should == 1
18
+
19
+ e = ex['exceptions'].first
20
+ e['name'].should == exception.class.to_s
21
+ e['message'].should == CGI.escape(exception.message)
22
+ e['backtrace'].should == exception.backtrace
23
+ e['short_name'].should == exception.class.to_s.split('::').last
24
+ end
25
+
26
+ it "should generate an exceptions response" do
27
+ exceptions = [TestException.new('An exception'), TestException.new('Another exception')]
28
+
29
+ ex = JSON.parse(JSClientBridge::Responses.respond_with_exceptions(exceptions, :request_uri => '/', :parameters => {:param1 => 'value1'}))
30
+
31
+ ex['_status'].should == 'exception'
32
+ ex['request_uri'].should == '/'
33
+ ex['parameters'].should == {'param1' => 'value1'}
34
+ ex['exceptions'].length.should == 2
35
+ end
36
+
37
+ it "should require the request_uri option" do
38
+ lambda {
39
+ JSClientBridge::Responses.respond_with_exception(TestException.new('An exception'), :parameters => {:param1 => 'value1'})
40
+ }.should raise_error(ArgumentError)
41
+ end
42
+
43
+ it "should require the exception option" do
44
+ lambda {
45
+ JSClientBridge::Responses.respond_with_exception(:request_uri => '/', :parameters => {:param1 => 'value1'})
46
+ }.should raise_error(ArgumentError)
47
+ end
48
+
49
+ it "should generate an exception response using JSONP" do
50
+ exception = TestException.new('An exception')
51
+
52
+ ex = JSClientBridge::Responses.respond_with_exception(exception, :request_uri => '/', :parameters => {:param1 => 'value1'}, :jsonp => 'jsonp1')
53
+ ex[0..6].should == 'jsonp1('
54
+ ex[-1..-1].should == ')'
55
+ end
56
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+
4
+
5
+
6
+ describe "Ok Responses" do
7
+ it "should generate a basic ok response" do
8
+ JSClientBridge::Responses.respond_with_ok.should == {:_status => 'ok'}.to_json
9
+ end
10
+
11
+ it "should generate a ok response with a status message" do
12
+ JSClientBridge::Responses.respond_with_ok('a message').should == {:_status => 'ok', :_message => "a message"}.to_json
13
+ end
14
+
15
+ it "should generate a ok response with a status message and additional custom parameters" do
16
+ JSClientBridge::Responses.respond_with_ok('a message', :awesomeness => 'has happened').should == {:_status => 'ok', :_message => "a message", :awesomeness => 'has happened'}.to_json
17
+ end
18
+
19
+ it "should generate a ok response with a status message and a complex parameters" do
20
+ JSClientBridge::Responses.respond_with_ok('a message', :stuff => complext_test_data).should == {:_message => "a message", :stuff => complext_test_data, :_status => 'ok'}.to_json
21
+ end
22
+
23
+ it "should generate a basic ok response using JSONP" do
24
+ JSClientBridge::Responses.respond_with_ok('a message', :jsonp => 'jsonp1').should == "jsonp1(#{{:_status => 'ok', :_message => "a message"}.to_json})"
25
+ end
26
+
27
+ def complext_test_data
28
+ [
29
+ {:name=>"Whangarei",
30
+ :description=>"Northland Coach & Travel Centre, 3C Bank St.",
31
+ :id=>:WRE},
32
+ {:name=>"Westwood Lodge", :description=>"Westwood Lodge", :id=>:WWL},
33
+ {:name=>"Queenstown YHA Lake Esplanade",
34
+ :description=>"Queenstown YHA, 80 Lake Esplanade",
35
+ :id=>:YHQ},
36
+ {:name=>"Queenstown Airport", :description=>"Queenstown Airport", :id=>:ZQA},
37
+ {:name=>"Queenstown",
38
+ :description=>"Athol Street in the middle of the car park",
39
+ :id=>:ZQN},
40
+ {:name=>"Queenstown The Station",
41
+ :description=>"The Station, corner of Camp and Shotover Streets",
42
+ :id=>:ZQT}
43
+ ]
44
+ end
45
+ end
46
+
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,12 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'js-client-bridge'
11
+
12
+ require 'pp'
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'dm-core'
4
+ require 'dm-aggregates'
5
+ require 'dm-migrations'
6
+ require 'dm-timestamps'
7
+ require 'dm-types'
8
+ require 'dm-validations'
9
+
10
+ module Luma
11
+ module Test
12
+ class TestDO
13
+ include DataMapper::Resource
14
+
15
+ property :id, String, :key => true, :length => 36
16
+
17
+ property :subject, String, :length => 30..155, :nullable => false
18
+ property :body, Text, :nullable => false
19
+ end # class Message
20
+ end
21
+ end
22
+
23
+ describe "Validation Responses" do
24
+ before(:all) do
25
+ DataMapper.setup(:default, 'sqlite3::memory:')
26
+ DataMapper.auto_migrate!
27
+ end
28
+
29
+ it "should generate a basic validation response" do
30
+ test_do = Luma::Test::TestDO.new
31
+ test_do.save.should be_false
32
+
33
+ ex = JSON.parse(JSClientBridge::Responses.respond_with_validation_error(test_do))
34
+ pp ex
35
+ ex['validation'].length.should == 3
36
+ ex['_short_type'].should == "TestDO"
37
+ ex['_type'].should == "Luma::Test::TestDO"
38
+ end
39
+
40
+ it "should generate a basic validation response using JSONP" do
41
+ test_do = Luma::Test::TestDO.new
42
+ test_do.save.should be_false
43
+
44
+ ex = JSClientBridge::Responses.respond_with_validation_error(test_do, :jsonp => 'jsonp1')
45
+ ex[0..6].should == 'jsonp1('
46
+ ex[-1..-1].should == ')'
47
+ end
48
+ end
49
+
50
+
51
+ =begin
52
+ {
53
+ :_status => 'validation',
54
+ :_type => self.class,
55
+ :_short_type => self.class.to_s.split('::').first,
56
+ :_message => message,
57
+ :validation => self.errors.to_json
58
+ }
59
+
60
+ {
61
+ "validation"=> {
62
+ "body" => ["Body must not be blank"],
63
+ "subject" => ["Subject must not be blank", "Subject must be between 30 and 155 characters long"],
64
+ "id" => ["Id must not be blank"]
65
+ },
66
+ "_short_type" => "TestDO",
67
+ "_status" => "validation",
68
+ "_type" => "Luma::Test::TestDO",
69
+ "_message" => "Sorry, we couldn't save your TestDO"
70
+ }
71
+
72
+ =end
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: js-client-bridge
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Rolly
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-02 00:00:00 +13:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: extlib
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: rubyforge
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 2
53
+ - 0
54
+ - 4
55
+ version: 2.0.4
56
+ type: :development
57
+ version_requirements: *id003
58
+ - !ruby/object:Gem::Dependency
59
+ name: gemcutter
60
+ prerelease: false
61
+ requirement: &id004 !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ - 4
68
+ - 1
69
+ version: 0.4.1
70
+ type: :development
71
+ version_requirements: *id004
72
+ - !ruby/object:Gem::Dependency
73
+ name: hoe
74
+ prerelease: false
75
+ requirement: &id005 !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 2
81
+ - 5
82
+ - 0
83
+ version: 2.5.0
84
+ type: :development
85
+ version_requirements: *id005
86
+ description: Little library that encapsulates a (particular) standardised way of talking between a service and javascript. Probably not the best way of doing things, but it's been handy in a pinch.
87
+ email:
88
+ - rolly@luma.co.nz
89
+ executables: []
90
+
91
+ extensions: []
92
+
93
+ extra_rdoc_files:
94
+ - History.txt
95
+ - Manifest.txt
96
+ - README.txt
97
+ files:
98
+ - History.txt
99
+ - Manifest.txt
100
+ - README.txt
101
+ - Rakefile
102
+ - lib/js-client-bridge.rb
103
+ - lib/js-client-bridge/responses.rb
104
+ - lib/js-client-bridge/responses/ok.rb
105
+ - lib/js-client-bridge/responses/validation.rb
106
+ - lib/js-client-bridge/responses/error.rb
107
+ - lib/js-client-bridge/responses/exception.rb
108
+ - lib/js-client-bridge/extensions/datamapper_errors.rb
109
+ - script/console
110
+ - script/destroy
111
+ - script/generate
112
+ - spec/ok_responses_spec.rb
113
+ - spec/error_responses_spec.rb
114
+ - spec/exception_responses_spec.rb
115
+ - spec/validation_responses_spec.rb
116
+ - spec/spec.opts
117
+ - spec/spec_helper.rb
118
+ - tasks/rspec.rake
119
+ has_rdoc: true
120
+ homepage: https://github.com/luma/js-client-bridge/tree/master
121
+ licenses: []
122
+
123
+ post_install_message:
124
+ rdoc_options:
125
+ - --main
126
+ - README.txt
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ segments:
141
+ - 0
142
+ version: "0"
143
+ requirements: []
144
+
145
+ rubyforge_project: js-client-bridge
146
+ rubygems_version: 1.3.6
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: Little library that encapsulates a (particular) standardised way of talking between a service and javascript
150
+ test_files: []
151
+