appcelerator 2.0.1.1

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.
Files changed (93) hide show
  1. data/appcelerator/appcelerator_generator.rb +195 -0
  2. data/appcelerator/templates/README +26 -0
  3. data/appcelerator/templates/appcelerator.xml +8 -0
  4. data/appcelerator/templates/application.rb +7 -0
  5. data/appcelerator/templates/environment.rb +65 -0
  6. data/appcelerator/templates/generate +25 -0
  7. data/appcelerator/templates/images/appcelerator_gray_header.png +0 -0
  8. data/appcelerator/templates/images/appcelerator_gray_logo_small.png +0 -0
  9. data/appcelerator/templates/images/blank_1x1.gif +0 -0
  10. data/appcelerator/templates/images/confirm.png +0 -0
  11. data/appcelerator/templates/images/cross.png +0 -0
  12. data/appcelerator/templates/images/deny.png +0 -0
  13. data/appcelerator/templates/images/dialog_close.gif +0 -0
  14. data/appcelerator/templates/images/dialog_close_hover.gif +0 -0
  15. data/appcelerator/templates/images/email.png +0 -0
  16. data/appcelerator/templates/images/exclamation.png +0 -0
  17. data/appcelerator/templates/images/favicon.ico +0 -0
  18. data/appcelerator/templates/images/header.png +0 -0
  19. data/appcelerator/templates/images/indicator.gif +0 -0
  20. data/appcelerator/templates/images/indicator2.gif +0 -0
  21. data/appcelerator/templates/images/indicator3.gif +0 -0
  22. data/appcelerator/templates/images/logo.png +0 -0
  23. data/appcelerator/templates/images/shadow.gif +0 -0
  24. data/appcelerator/templates/images/shadowAlpha.png +0 -0
  25. data/appcelerator/templates/images/warning.png +0 -0
  26. data/appcelerator/templates/index.html +46 -0
  27. data/appcelerator/templates/js/appcelerator-debug.js +16658 -0
  28. data/appcelerator/templates/js/appcelerator.js +20 -0
  29. data/appcelerator/templates/modules/app_calendar/app_calendar.js +1 -0
  30. data/appcelerator/templates/modules/app_calendar/css/calendar.css +1 -0
  31. data/appcelerator/templates/modules/app_calendar/images/callt.gif +0 -0
  32. data/appcelerator/templates/modules/app_calendar/images/calrt.gif +0 -0
  33. data/appcelerator/templates/modules/app_calendar/images/calx.gif +0 -0
  34. data/appcelerator/templates/modules/app_calendar/js/calendar.js +1 -0
  35. data/appcelerator/templates/modules/app_calendar/js/dom.js +1 -0
  36. data/appcelerator/templates/modules/app_calendar/js/event.js +1 -0
  37. data/appcelerator/templates/modules/app_calendar/js/yahoo.js +1 -0
  38. data/appcelerator/templates/modules/app_chart/app_chart.js +1 -0
  39. data/appcelerator/templates/modules/app_chart/js/swfobject.js +1 -0
  40. data/appcelerator/templates/modules/app_content/app_content.js +1 -0
  41. data/appcelerator/templates/modules/app_datacache/app_datacache.js +1 -0
  42. data/appcelerator/templates/modules/app_datatable/app_datatable.js +1 -0
  43. data/appcelerator/templates/modules/app_datatable/css/datatable.css +1 -0
  44. data/appcelerator/templates/modules/app_datatable/images/arrow_down.png +0 -0
  45. data/appcelerator/templates/modules/app_datatable/images/arrow_spacer.png +0 -0
  46. data/appcelerator/templates/modules/app_datatable/images/arrow_up.png +0 -0
  47. data/appcelerator/templates/modules/app_datatable/images/resultset_next.png +0 -0
  48. data/appcelerator/templates/modules/app_datatable/images/resultset_previous.png +0 -0
  49. data/appcelerator/templates/modules/app_editinplace/app_editinplace.js +1 -0
  50. data/appcelerator/templates/modules/app_editinplace/css/editinplace.css +1 -0
  51. data/appcelerator/templates/modules/app_editinplace/images/bullet_error.png +0 -0
  52. data/appcelerator/templates/modules/app_field/app_field.js +1 -0
  53. data/appcelerator/templates/modules/app_field/css/field.css +1 -0
  54. data/appcelerator/templates/modules/app_field/images/bullet_error.png +0 -0
  55. data/appcelerator/templates/modules/app_folder/app_folder.js +1 -0
  56. data/appcelerator/templates/modules/app_folder/css/folder.css +1 -0
  57. data/appcelerator/templates/modules/app_folder/images/folder_closed.png +0 -0
  58. data/appcelerator/templates/modules/app_folder/images/folder_opened.png +0 -0
  59. data/appcelerator/templates/modules/app_folder/images/item_closed.png +0 -0
  60. data/appcelerator/templates/modules/app_folder/images/item_opened.png +0 -0
  61. data/appcelerator/templates/modules/app_iterator/app_iterator.js +1 -0
  62. data/appcelerator/templates/modules/app_message/app_message.js +1 -0
  63. data/appcelerator/templates/modules/app_modaldialog/app_modaldialog.js +1 -0
  64. data/appcelerator/templates/modules/app_modaldialog/css/modaldialog.css +1 -0
  65. data/appcelerator/templates/modules/app_pagination/app_pagination.js +1 -0
  66. data/appcelerator/templates/modules/app_script/app_script.js +1 -0
  67. data/appcelerator/templates/modules/app_security/app_security.js +1 -0
  68. data/appcelerator/templates/modules/app_statemachine/app_statemachine.js +1 -0
  69. data/appcelerator/templates/modules/app_tabpanel/app_tabpanel.js +1 -0
  70. data/appcelerator/templates/modules/app_tabpanel/css/tabpanel.css +1 -0
  71. data/appcelerator/templates/modules/app_template/app_template.js +1 -0
  72. data/appcelerator/templates/modules/app_upload/app_upload.js +1 -0
  73. data/appcelerator/templates/modules/app_validation/app_validation.js +1 -0
  74. data/appcelerator/templates/modules/google_analytics/google_analytics.js +1 -0
  75. data/appcelerator/templates/routes.rb +18 -0
  76. data/appcelerator/templates/server +4 -0
  77. data/appcelerator/templates/service_broker.rb +18 -0
  78. data/appcelerator/templates/service_broker_helper.rb +2 -0
  79. data/appcelerator/templates/test_service.rb +13 -0
  80. data/bin/appcelerator +36 -0
  81. data/lib/appcelerator.rb +62 -0
  82. data/lib/appcelerator/active_record_extension.rb +11 -0
  83. data/lib/appcelerator/dispatcher.rb +68 -0
  84. data/lib/appcelerator/migration.rb +8 -0
  85. data/lib/appcelerator/model.rb +94 -0
  86. data/lib/appcelerator/service.rb +292 -0
  87. data/lib/appcelerator/service_broker.rb +12 -0
  88. data/lib/appcelerator/service_broker_controller.rb +48 -0
  89. data/lib/appcelerator/servicebroker/inmemory_service_broker.rb +58 -0
  90. data/service/USAGE +20 -0
  91. data/service/service_generator.rb +59 -0
  92. data/service/templates/service.rb +14 -0
  93. metadata +204 -0
@@ -0,0 +1,292 @@
1
+
2
+
3
+ module Appcelerator
4
+ class Service
5
+ include Singleton
6
+
7
+ def Service.Service(messagetype,handler,responsetype)
8
+ self.instance.preregister(messagetype,handler,responsetype)
9
+ end
10
+
11
+ def Service.service_scaffold(model)
12
+ servicename = model_name(model)
13
+ self.instance.model_class = eval(model.to_s.camelize)
14
+ %w(create retrieve update delete list assembly search).each do |operation|
15
+ messagetype = "app."+ servicename +"."+ operation
16
+ request = messagetype + ".request"
17
+ response = messagetype + ".response"
18
+ self.instance.preregister(request,operation,response)
19
+ APP_SERVICES << {'name'=>name, 'model'=>servicename}
20
+ end
21
+ end
22
+
23
+ #
24
+ # The following methods are usable by services that call the "service_scaffold" method
25
+ # to provide CRUD (and more) operations on a single model object.
26
+ #
27
+ def assembly(request,message)
28
+ if self.respond_to?(:before_assembly)
29
+ request,message = send(:before_assembly,request,message)
30
+ end
31
+ data = Array.new
32
+ @model_class.columns.each do |column|
33
+ data << {'name'=>column.name,'type'=>column.type, 'limit'=>column.limit,
34
+ 'nullable'=>column.null, 'primary'=>column.primary,
35
+ 'default'=>column.default}
36
+ end
37
+ response = {'success'=>true,'columns'=>data}
38
+ if self.respond_to?(:after_assembly)
39
+ response = send(:after_assembly,response)
40
+ end
41
+ response
42
+ end
43
+
44
+ def create(request,message)
45
+ if self.respond_to?(:before_create)
46
+ request,message = send(:before_create,request,message)
47
+ end
48
+ o = @model_class.new(message)
49
+ o.save
50
+ response = {'success'=>true,'id'=>o.id}
51
+ if self.respond_to?(:after_create)
52
+ response = send(:after_create,response)
53
+ end
54
+ response
55
+ end
56
+
57
+ def retrieve(request,message)
58
+ if self.respond_to?(:before_retrieve)
59
+ request,message = send(:before_retrieve,request,message)
60
+ end
61
+ o = @model_class.find(message['id'])
62
+ response = {'success'=>true}
63
+ o.attributes.each do |key,val|
64
+ response[key]=val
65
+ end
66
+ response
67
+ if self.respond_to?(:after_retrieve)
68
+ response = send(:after_retrieve,response)
69
+ end
70
+ response
71
+ end
72
+
73
+ def update(request,message)
74
+ if self.respond_to?(:before_update)
75
+ request,message = send(:before_update,request,message)
76
+ end
77
+ o = @model_class.find(message['id'])
78
+ return {'success'=>false,'message'=>'record does not exist'} unless o
79
+ message.each do |key,value|
80
+ if o.attributes.has_key?(key)
81
+ o[key]=true if value=='true'
82
+ o[key]=false if value=='false'
83
+ o[key]=value if o[key]!=true && o[key]!=false
84
+ end
85
+ end
86
+ o.save!
87
+ response = {'success'=>true,'id'=>o.id}
88
+ if self.respond_to?(:after_update)
89
+ response = send(:after_update,response)
90
+ end
91
+ response
92
+ end
93
+
94
+ def delete(request,message)
95
+ if self.respond_to?(:before_delete)
96
+ request,message = send(:before_delete,request,message)
97
+ end
98
+ @model_class.delete(message['id'])
99
+ response = {'success'=>true,'id'=>message['id']}
100
+ if self.respond_to?(:after_delete)
101
+ response = send(:after_delete,response)
102
+ end
103
+ response
104
+ end
105
+
106
+ def search(request,message)
107
+ if self.respond_to?(:before_search)
108
+ request,message = send(:before_search,request,message)
109
+ end
110
+ query = '%%' + message['query'] + '%%'
111
+ conditions_str = Array.new
112
+ @model_class.content_columns.each do |col|
113
+ name = col.name + ' like ?'
114
+ conditions_str << name if col.type == :string
115
+ end
116
+
117
+ conditions = Array.new
118
+ conditions << conditions_str.join(' OR ')
119
+ conditions_str.length.times {|e| conditions<<query}
120
+
121
+ results = @model_class.find(:all,:conditions=>conditions)
122
+ response = {'success'=>true, 'rows'=>results, 'total'=>@model_class.count, 'count'=>results.length}
123
+
124
+ if self.respond_to?(:after_search)
125
+ response = send(:after_search,response)
126
+ end
127
+ response
128
+ end
129
+
130
+ def list(request,message)
131
+ pk = message['id']
132
+ limit = message['limit'] || 100
133
+ if pk
134
+ objs = [@model_class.find_by_id(pk)]
135
+ else
136
+ objs = @model_class.find(:all,:limit=>limit)
137
+ end
138
+ response = {'success'=>true,'rows'=>objs, 'total'=>@model_class.count}
139
+ if self.respond_to?(:after_list)
140
+ response = send(:after_list,response)
141
+ end
142
+ response
143
+ end
144
+
145
+
146
+ def self.load_services
147
+ APP_SERVICES.clear
148
+ # TODO: remove this and solve the multiple singleton issue
149
+ Appcelerator::ServiceBroker.clear_listeners
150
+ Dir[RAILS_ROOT + '/app/services/*_service.rb'].each do |file|
151
+
152
+ name = Inflector.camelize(File.basename(file).chomp('_service.rb')) + 'Service'
153
+
154
+ if Dependencies.load?
155
+ if defined?(name)
156
+ klass = eval(name)
157
+ # clear the service class's existing listeners, if possible
158
+ klass.instance.clear_listeners
159
+ end
160
+ load file
161
+ else
162
+ require file[0..-4]
163
+ end
164
+
165
+ begin
166
+ klass = eval(name)
167
+ klass.instance.register_listeners
168
+ rescue
169
+ puts 'Unable to find class "'+ name +'" in file "'+ file +'"'
170
+ puts $!
171
+ end
172
+ end
173
+ puts 'done loading services'
174
+ puts Appcelerator::ServiceBroker.diagnostics
175
+ end
176
+
177
+ def initialize
178
+ @listeners = []
179
+ @preregistrations = []
180
+ end
181
+
182
+ def preregister(*args)
183
+ @preregistrations << args
184
+ end
185
+
186
+ def register_listeners
187
+ # call after class-load when all methods are defined
188
+ @listeners = @preregistrations.map do |reg|
189
+ register(*reg)
190
+ end
191
+ @preregistrations.clear
192
+ @listeners.length
193
+ end
194
+
195
+ def clear_listeners
196
+ num_cleared = @listeners.length
197
+ @listeners.each do |listener|
198
+ ServiceBroker.unregister_listener(listener.msgtype, listener)
199
+ end
200
+ @listeners.clear
201
+ num_cleared
202
+ end
203
+
204
+ def register(msgtype,methodname,responsetype = nil)
205
+ service = self.class # add to the ServiceProc binding
206
+ handler = self.method(methodname)
207
+ args = handler.arity
208
+ proc = ServiceProc.new do |req,msgtype,obj|
209
+
210
+ #
211
+ # try and be smart about sending in the request to the
212
+ # service based on the arguments he supports
213
+ #
214
+ case args
215
+ when 2
216
+ resp = handler.call(req,obj)
217
+ when 3
218
+ resp = handler.call(req,obj,req['session'])
219
+ when 4
220
+ resp = handler.call(req,obj,req['session'],req['session']['username'])
221
+ end
222
+
223
+ if responsetype
224
+ Dispatcher.instance.outgoing(req,responsetype,resp||{})
225
+ end
226
+ end
227
+ ServiceBroker.register_listener(msgtype,proc)
228
+ proc
229
+ end
230
+
231
+ def send_message(req,type,message)
232
+ ServiceBroker.send(req,type,message)
233
+ end
234
+
235
+ def secure_password_matches?(request,message,password_field,password)
236
+
237
+ password_obj = message[password_field]
238
+
239
+ if password_obj
240
+ return Digest::MD5.hexdigest(password + request['authtoken']) == password_obj['auth']
241
+ end
242
+
243
+ false
244
+ end
245
+ end
246
+
247
+ #
248
+ # Class to allow inspection and equality checking (for adding to sets)
249
+ # TODO: remove the to_s in eql? and hash when the singleton issue is resolved
250
+ #
251
+ class ServiceProc < Proc
252
+ def self.vars
253
+ [:msgtype, :service, :methodname, :responsetype]
254
+ end
255
+
256
+ def method_missing name
257
+ eval(name.to_s, self.binding)
258
+ end
259
+
260
+ def to_s
261
+ "#{msgtype} -> #{service}.#{methodname} -> #{responsetype}"
262
+ end
263
+
264
+ def eql?(other)
265
+ self.class.vars.all? do |var|
266
+ self.send(var).to_s == other.send(var).to_s
267
+ end
268
+ end
269
+ alias :== :eql?
270
+
271
+ def hash
272
+ val = 1
273
+ self.class.vars.each do |var|
274
+ val << 4
275
+ val += self.send(var).to_s.hash
276
+ end
277
+ val
278
+ end
279
+ end
280
+
281
+ # helper method
282
+ class Array
283
+ def all? &pred
284
+ each do |e|
285
+ if not pred.call(e)
286
+ return false
287
+ end
288
+ end
289
+ return true
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # require dependencies
3
+ #
4
+ Dir[File.dirname(__FILE__)+'/servicebroker/*.rb'].sort.each do |file|
5
+ require file[0..-4]
6
+ end
7
+
8
+
9
+ #
10
+ # set the default service broker to the basic in memory service broker
11
+ #
12
+ Appcelerator::ServiceBroker = Appcelerator::InmemoryServiceBroker.instance
@@ -0,0 +1,48 @@
1
+ require 'digest/md5'
2
+
3
+ module RequestMixin
4
+ def authtoken=(t)
5
+ @_authtoken = t
6
+ end
7
+ def authtoken
8
+ @_authtoken
9
+ end
10
+ end
11
+
12
+ module ServiceBroker
13
+
14
+ @logger = nil
15
+
16
+ def log_processing
17
+ # turn off logging since we get a lot of these requests
18
+ end
19
+
20
+ def dispatch
21
+
22
+ if not @logger
23
+ @logger = Appcelerator::Model.logger
24
+ end
25
+
26
+ session = request.session
27
+
28
+ # we check to make sure we're coming from an XHR request
29
+ # this is easy to forge but a simple check
30
+ #
31
+ if not request.xml_http_request? and not request.xhr?
32
+ @logger.error("client error = not XHR request")
33
+ session.delete
34
+ render :nothing => true, :status => 400
35
+ return
36
+ end
37
+
38
+ response.headers['Content-Type'] = 'text/xml'
39
+ response.headers['Pragma'] = 'no-cache'
40
+ response.headers['Cache-Control'] = 'no-cache, no-store, private, must-revalidate'
41
+ response.headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'
42
+
43
+ Appcelerator::Dispatcher.instance.incoming(session,request,response)
44
+ Appcelerator::Dispatcher.instance.serialize(session,response.body)
45
+
46
+ @performed_render = true
47
+ end
48
+ end
@@ -0,0 +1,58 @@
1
+ #
2
+ # implementation of the service broker which only dispatches
3
+ # messages to internally registered listeners
4
+ #
5
+ #
6
+ require 'set'
7
+ module Appcelerator
8
+ class InmemoryServiceBroker
9
+ include Singleton
10
+
11
+ def initialize
12
+ @listeners={}
13
+ end
14
+
15
+ def register_listener(msgtype,listener)
16
+ begin
17
+ @listeners[msgtype] << listener
18
+ rescue
19
+ @listeners[msgtype] = Set.new << listener
20
+ end
21
+ end
22
+
23
+ def unregister_listener(msgtype,listener)
24
+ array = @listeners[msgtype]
25
+ array.delete_if { |a| a == listener } if array
26
+ end
27
+
28
+ def clear_listeners
29
+ @listeners.clear
30
+ end
31
+
32
+ def send (req,type,obj)
33
+ array = @listeners[type]
34
+ if array
35
+ array.each do |listener|
36
+ begin
37
+ listener.call(req,type,obj)
38
+ rescue => error
39
+ puts $!
40
+ raise error
41
+ end
42
+ end
43
+ return true
44
+ end
45
+ false
46
+ end
47
+
48
+ def diagnostics
49
+ all = []
50
+ @listeners.each do |k,v|
51
+ v.each do |proc|
52
+ all << proc.to_s
53
+ end
54
+ end
55
+ all.join "\n"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ Description:
2
+ The generator creates stubs for a new Appcelerator Service.
3
+
4
+ The generator takes a class name, message type and method name as arguments.
5
+ The messagehandler name may be given in CamelCase or under_score and should
6
+ not be suffixed with 'Service'.
7
+
8
+ The generator creates a service class in app/services.
9
+
10
+ ./script/generate service <ServiceClassName> <ServiceMessageRequest> <ServiceMethod> [ServiceMessageResponse]
11
+
12
+ The following are the arguments:
13
+
14
+ ServiceClassName - name of the service class
15
+ ServiceMessageRequest - message request type
16
+ ServiceMethod - method name to call
17
+
18
+ Example:
19
+ ./script/generate service CreditCard service.creditcard.charge.request charge [service.creditcard.charge.response]
20
+
@@ -0,0 +1,59 @@
1
+ require 'action_controller'
2
+ require 'active_record'
3
+
4
+ class ServiceGenerator < Rails::Generator::NamedBase
5
+
6
+ def initialize(runtime_args, runtime_options = {})
7
+ super
8
+ usage if args.empty?
9
+
10
+ @messagename = args.shift rescue usage
11
+ @messagetype = args.shift rescue usage
12
+ @messagefunc = args.shift rescue usage
13
+ @responsemsg = args.shift rescue nil
14
+
15
+ usage if @messagename==nil
16
+ usage if @messagetype==nil
17
+ usage if @messagefunc==nil
18
+
19
+ # trim off : if they use it
20
+ if @messagefunc[0] == 58
21
+ @messagefunc = @messagefunc.slice(1..@messagefunc.length)
22
+ end
23
+
24
+ camel = @messagename.camelize
25
+ under = camel.underscore
26
+
27
+ @messageFile = under.downcase + '_service.rb'
28
+ @messageClass = camel + 'Service'
29
+ end
30
+
31
+ def usage_message
32
+ File.read(File.join(File.dirname(__FILE__), 'USAGE')) rescue ''
33
+ end
34
+
35
+ def manifest
36
+ record do |m|
37
+ # Check for class naming collisions.
38
+ m.class_collisions @messageClass
39
+
40
+ # make sure we have a services dir
41
+ m.directory File.join('app/services', class_path)
42
+
43
+ responsetype = ''
44
+ response = ''
45
+
46
+ if @responsemsg
47
+ responsetype = ", '#{@responsemsg}'"
48
+ response = '{"success"=>true}'
49
+ end
50
+
51
+ # message handler template
52
+ m.template 'service/templates/service.rb',
53
+ File.join('app/services',
54
+ class_path,
55
+ "#{@messageFile}"),
56
+ :assigns => {'messageclass'=>@messageClass, 'messagetype'=>@messagetype, 'messagefunc'=>@messagefunc, 'responsetype'=>responsetype, 'response'=>response}
57
+ end
58
+ end
59
+ end