dima-restfulx 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/History.txt +7 -0
  2. data/Manifest.txt +127 -0
  3. data/README.rdoc +50 -0
  4. data/Rakefile +42 -0
  5. data/app_generators/rx_app/USAGE +22 -0
  6. data/app_generators/rx_app/rx_app_generator.rb +94 -0
  7. data/app_generators/rx_app/templates/actionscript.properties +16 -0
  8. data/app_generators/rx_app/templates/actionscriptair.properties +16 -0
  9. data/app_generators/rx_app/templates/app.yaml.erb +12 -0
  10. data/app_generators/rx_app/templates/default_tasks.rake +51 -0
  11. data/app_generators/rx_app/templates/empty.txt +0 -0
  12. data/app_generators/rx_app/templates/expressInstall.swf +0 -0
  13. data/app_generators/rx_app/templates/flex.properties +2 -0
  14. data/app_generators/rx_app/templates/generate.rb +17 -0
  15. data/app_generators/rx_app/templates/html-template/AC_OETags.js +276 -0
  16. data/app_generators/rx_app/templates/html-template/history/history.css +6 -0
  17. data/app_generators/rx_app/templates/html-template/history/history.js +645 -0
  18. data/app_generators/rx_app/templates/html-template/history/historyFrame.html +29 -0
  19. data/app_generators/rx_app/templates/html-template/index.template.html +121 -0
  20. data/app_generators/rx_app/templates/html-template/playerProductInstall.swf +0 -0
  21. data/app_generators/rx_app/templates/index.html.erb +18 -0
  22. data/app_generators/rx_app/templates/index.yaml +11 -0
  23. data/app_generators/rx_app/templates/mainair-app.xml +134 -0
  24. data/app_generators/rx_app/templates/mainapp-config.xml +21 -0
  25. data/app_generators/rx_app/templates/mainapp.mxml +31 -0
  26. data/app_generators/rx_app/templates/project-textmate.erb +52 -0
  27. data/app_generators/rx_app/templates/project.properties +18 -0
  28. data/app_generators/rx_app/templates/projectair.properties +24 -0
  29. data/app_generators/rx_app/templates/swfobject.js +5 -0
  30. data/bin/rx-gen +31 -0
  31. data/generators/rx_config/USAGE +5 -0
  32. data/generators/rx_config/rx_config_generator.rb +19 -0
  33. data/generators/rx_controller/USAGE +10 -0
  34. data/generators/rx_controller/rx_controller_generator.rb +39 -0
  35. data/generators/rx_controller/templates/assist.py +65 -0
  36. data/generators/rx_controller/templates/controller.as.erb +36 -0
  37. data/generators/rx_controller/templates/restful.py +136 -0
  38. data/generators/rx_main_app/USAGE +8 -0
  39. data/generators/rx_main_app/rx_main_app_generator.rb +60 -0
  40. data/generators/rx_main_app/templates/main.py.erb +29 -0
  41. data/generators/rx_main_app/templates/mainapp.mxml +35 -0
  42. data/generators/rx_scaffold/USAGE +29 -0
  43. data/generators/rx_scaffold/rx_scaffold_generator.rb +146 -0
  44. data/generators/rx_scaffold/templates/component.mxml.erb +149 -0
  45. data/generators/rx_scaffold/templates/controller.py.erb +27 -0
  46. data/generators/rx_scaffold/templates/model.as.erb +42 -0
  47. data/generators/rx_scaffold/templates/model.py.erb +14 -0
  48. data/generators/rx_yaml_scaffold/USAGE +45 -0
  49. data/generators/rx_yaml_scaffold/rx_yaml_scaffold_generator.rb +47 -0
  50. data/lib/restfulx/active_foo.rb +186 -0
  51. data/lib/restfulx/active_record_tasks.rb +81 -0
  52. data/lib/restfulx/configuration.rb +76 -0
  53. data/lib/restfulx/datamapper_foo.rb +31 -0
  54. data/lib/restfulx/rails/recipes.rb +60 -0
  55. data/lib/restfulx/rails/swf_helper.rb +60 -0
  56. data/lib/restfulx/tasks.rb +85 -0
  57. data/lib/restfulx.rb +117 -0
  58. data/rails_generators/rx_config/USAGE +18 -0
  59. data/rails_generators/rx_config/rx_config_generator.rb +115 -0
  60. data/rails_generators/rx_config/templates/actionscript.properties +16 -0
  61. data/rails_generators/rx_config/templates/actionscriptair.properties +16 -0
  62. data/rails_generators/rx_config/templates/expressInstall.swf +0 -0
  63. data/rails_generators/rx_config/templates/flex.properties +2 -0
  64. data/rails_generators/rx_config/templates/html-template/AC_OETags.js +276 -0
  65. data/rails_generators/rx_config/templates/html-template/history/history.css +6 -0
  66. data/rails_generators/rx_config/templates/html-template/history/history.js +645 -0
  67. data/rails_generators/rx_config/templates/html-template/history/historyFrame.html +29 -0
  68. data/rails_generators/rx_config/templates/html-template/index.template.html +121 -0
  69. data/rails_generators/rx_config/templates/html-template/playerProductInstall.swf +0 -0
  70. data/rails_generators/rx_config/templates/index.html.erb +18 -0
  71. data/rails_generators/rx_config/templates/mainair-app.xml +134 -0
  72. data/rails_generators/rx_config/templates/mainapp-config.xml +21 -0
  73. data/rails_generators/rx_config/templates/mainapp.mxml +31 -0
  74. data/rails_generators/rx_config/templates/project-textmate.erb +52 -0
  75. data/rails_generators/rx_config/templates/project.properties +18 -0
  76. data/rails_generators/rx_config/templates/projectair.properties +24 -0
  77. data/rails_generators/rx_config/templates/restfulx.yml +14 -0
  78. data/rails_generators/rx_config/templates/restfulx_tasks.rake +6 -0
  79. data/rails_generators/rx_config/templates/swfobject.js +5 -0
  80. data/rails_generators/rx_controller/USAGE +10 -0
  81. data/rails_generators/rx_controller/rx_controller_generator.rb +28 -0
  82. data/rails_generators/rx_controller/templates/controller.as.erb +40 -0
  83. data/rails_generators/rx_scaffold/USAGE +35 -0
  84. data/rails_generators/rx_scaffold/rx_scaffold_generator.rb +179 -0
  85. data/rails_generators/rx_scaffold/templates/component.mxml.erb +149 -0
  86. data/rails_generators/rx_scaffold/templates/controller.rb.erb +97 -0
  87. data/rails_generators/rx_scaffold/templates/fixtures.yml.erb +35 -0
  88. data/rails_generators/rx_scaffold/templates/migration.rb.erb +19 -0
  89. data/rails_generators/rx_scaffold/templates/model.as.erb +42 -0
  90. data/rails_generators/rx_scaffold/templates/model.rb.erb +11 -0
  91. data/rails_generators/rx_yaml_scaffold/USAGE +51 -0
  92. data/rails_generators/rx_yaml_scaffold/rx_yaml_scaffold_generator.rb +49 -0
  93. data/rdoc/generators/template/html/jamis.rb +588 -0
  94. data/spec/restfulx_spec.rb +7 -0
  95. data/spec/spec_helper.rb +16 -0
  96. data/test/rails/controllers/application.rb +15 -0
  97. data/test/rails/controllers/locations_controller.rb +93 -0
  98. data/test/rails/controllers/notes_controller.rb +96 -0
  99. data/test/rails/controllers/projects_controller.rb +93 -0
  100. data/test/rails/controllers/tasks_controller.rb +93 -0
  101. data/test/rails/controllers/users_controller.rb +93 -0
  102. data/test/rails/database.yml +4 -0
  103. data/test/rails/fixtures/locations.yml +8 -0
  104. data/test/rails/fixtures/notes.yml +17 -0
  105. data/test/rails/fixtures/projects.yml +25 -0
  106. data/test/rails/fixtures/simple_properties.yml +19 -0
  107. data/test/rails/fixtures/tasks.yml +46 -0
  108. data/test/rails/fixtures/users.yml +13 -0
  109. data/test/rails/helpers/functional_test_helper.rb +21 -0
  110. data/test/rails/helpers/test_helper.rb +61 -0
  111. data/test/rails/helpers/unit_test_helper.rb +30 -0
  112. data/test/rails/model.yml +35 -0
  113. data/test/rails/models/location.rb +4 -0
  114. data/test/rails/models/note.rb +3 -0
  115. data/test/rails/models/project.rb +4 -0
  116. data/test/rails/models/simple_property.rb +2 -0
  117. data/test/rails/models/task.rb +18 -0
  118. data/test/rails/models/user.rb +20 -0
  119. data/test/rails/playing_around_in_a_console.txt +71 -0
  120. data/test/rails/schema.rb +77 -0
  121. data/test/rails/test.swf +1 -0
  122. data/test/rails/test_active_foo.rb +36 -0
  123. data/test/rails/test_rails_integration_functional.rb +22 -0
  124. data/test/rails/test_to_fxml.rb +35 -0
  125. data/test/rails/test_to_json.rb +23 -0
  126. data/test/rails/views/notes/empty_params_action.html.erb +1 -0
  127. data/test/rails/views/notes/index.html.erb +1 -0
  128. metadata +211 -0
@@ -0,0 +1,36 @@
1
+ package <%= base_package %>.controllers {
2
+ import <%= base_package %>.models.*;
3
+ import <%= base_package %>.commands.*;
4
+
5
+ import mx.core.Application;
6
+ import org.restfulx.Rx;
7
+ import org.restfulx.controllers.RxApplicationController;
8
+ import org.restfulx.utils.RxUtils;
9
+
10
+ public class <%= command_controller_name %> extends RxApplicationController {
11
+ private static var controller:<%= command_controller_name %>;
12
+
13
+ public static var models:Array = [<%= model_names %>]; /* Models */
14
+
15
+ public static var commands:Array = [<%= command_names %>]; /* Commands */
16
+
17
+ public function <%= command_controller_name %>(enforcer:SingletonEnforcer, extraServices:Array,
18
+ defaultServiceId:int = -1) {
19
+ super(commands, models, extraServices, defaultServiceId);
20
+ }
21
+
22
+ public static function get instance():<%= command_controller_name %> {
23
+ if (controller == null) initialize();
24
+ return controller;
25
+ }
26
+
27
+ public static function initialize(extraServices:Array = null, defaultServiceId:int = -1,
28
+ airDatabaseName:String = null):void {
29
+ if (!RxUtils.isEmpty(airDatabaseName)) Rx.airDatabaseName = airDatabaseName;
30
+ controller = new <%= command_controller_name %>(new SingletonEnforcer, extraServices,
31
+ defaultServiceId);
32
+ }
33
+ }
34
+ }
35
+
36
+ class SingletonEnforcer {}
@@ -0,0 +1,136 @@
1
+ # The MIT License
2
+ #
3
+ # Copyright (c) 2008 William T. Katz
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to
7
+ # deal in the Software without restriction, including without limitation
8
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ # and/or sell copies of the Software, and to permit persons to whom the
10
+ # Software is furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ # DEALINGS IN THE SOFTWARE.
22
+
23
+ """
24
+ RESTful Controller
25
+
26
+ We want our RESTful controllers to simply throw up their hands if they get
27
+ an unhandled HTTP verb. This is better for rich clients and server load
28
+ than throwing back lots of useless HTML.
29
+
30
+ These inherited methods should be overridden if there's a chance a human
31
+ browser is involved.
32
+
33
+ TODO: Return more information HTTP status codes that won't autotrip
34
+ browser login forms. For example, return status 405 (Method not allowed)
35
+ with an Allow header containing the list of valid methods.
36
+ """
37
+ __author__ = 'William T. Katz'
38
+
39
+ from google.appengine.ext import webapp
40
+
41
+ import logging
42
+
43
+ # Some useful module methods
44
+ def send_successful_response(handler, response):
45
+ logging.debug("Sending successful response: %s", response)
46
+ handler.response.headers["Content-Type"] = "application/xml"
47
+ handler.response.out.write('<?xml version="1.0" encoding="UTF-8"?>')
48
+ handler.response.out.write(response)
49
+
50
+ def get_model_key(handler):
51
+ return handler.request.path_info.split("/").pop().replace(".xml", "")
52
+
53
+ def get_sent_properties(request_func, propname_list):
54
+ """
55
+ This maps request strings to values in a hash, optionally run through
56
+ a function with previous request values as parameters to the func.
57
+ 1) key -> just read in the corresponding request value
58
+ 2) tuple (key, func) -> Read the request value for the string key
59
+ and pass it through func
60
+ 3) tuple (key, func, additional keys...) -> Get the request
61
+ values for the additional keys and pass them through func
62
+ before setting the key's value with the output.
63
+ If a key is not present in the request, then we do not insert a key
64
+ with None or empty string. The key is simply absent, therefore allowing
65
+ you to use the returned hash to initial a Model instance.
66
+ """
67
+ prop_hash = {}
68
+ for item in propname_list:
69
+ if isinstance(item, basestring):
70
+ key = item
71
+ value = request_func(item)
72
+ elif isinstance(item, tuple):
73
+ key = item[0]
74
+ prop_func = item[1]
75
+ if len(item) <= 2:
76
+ value = prop_func(request_func(key))
77
+ else:
78
+ try:
79
+ addl_keys = map(prop_hash.get, item[2:])
80
+ value = prop_func(*addl_keys)
81
+ except:
82
+ return None
83
+ if value:
84
+ prop_hash[key] = value
85
+ return prop_hash
86
+
87
+ def methods_via_query_allowed(handler_method):
88
+ """
89
+ A decorator to automatically re-route overloaded POSTs
90
+ that specify the real HTTP method in a _method query string.
91
+
92
+ To use it, decorate your post method like this:
93
+
94
+ import restful
95
+ ...
96
+ @restful.methods_via_query_allowed
97
+ def post(self):
98
+ pass
99
+
100
+ The decorator will check for a _method query string or POST argument,
101
+ and if present, will redirect to delete(), put(), etc.
102
+ """
103
+ def redirect_if_needed(self, *args, **kwargs):
104
+ real_verb = self.request.get('_method', None)
105
+ if not real_verb and 'X-HTTP-Method-Override' in self.request.environ:
106
+ real_verb = self.request.environ['X-HTTP-Method-Override']
107
+ if real_verb:
108
+ logging.debug("Redirected from POST. Detected method override = %s", real_verb)
109
+ method = real_verb.upper()
110
+ if method == 'HEAD':
111
+ self.head(*args, **kwargs)
112
+ elif method == 'PUT':
113
+ self.put(*args, **kwargs)
114
+ elif method == 'DELETE':
115
+ self.delete(*args, **kwargs)
116
+ elif method == 'TRACE':
117
+ self.trace(*args, **kwargs)
118
+ elif method == 'OPTIONS':
119
+ self.head(*args, **kwargs)
120
+ # POST and GET included for completeness
121
+ elif method == 'POST':
122
+ self.post(*args, **kwargs)
123
+ elif method == 'GET':
124
+ self.get(*args, **kwargs)
125
+ else:
126
+ self.error(405)
127
+ else:
128
+ handler_method(self, *args, **kwargs)
129
+ return redirect_if_needed
130
+
131
+ class Controller(webapp.RequestHandler):
132
+ def get(self, *params):
133
+ self.redirect("/403.html")
134
+
135
+ def head(self, *params):
136
+ pass
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Refreshes main Flex/AIR application file to make sure that
3
+ any of the generated components are included. Warning,
4
+ this will wipe your main application file. Used mostly
5
+ during code generation phase.
6
+
7
+ Examples:
8
+ `./script/generate rx_main_app`
@@ -0,0 +1,60 @@
1
+ class RxMainAppGenerator < RubiGen::Base
2
+ include RestfulX::Configuration
3
+
4
+ attr_reader :project_name,
5
+ :flex_project_name,
6
+ :base_package,
7
+ :base_folder,
8
+ :command_controller_name,
9
+ :model_names,
10
+ :component_names,
11
+ :controller_names,
12
+ :use_air,
13
+ :use_gae,
14
+ :application_tag
15
+
16
+ def initialize(runtime_args, runtime_options = {})
17
+ super
18
+ @project_name, @flex_project_name, @command_controller_name, @base_package, @base_folder = extract_names
19
+
20
+ project_file_name = APP_ROOT + '/.project'
21
+ if File.exist?(project_file_name)
22
+ @use_air = true if File.read(project_file_name) =~/com.adobe.flexbuilder.apollo.apollobuilder/m
23
+ end
24
+
25
+ if @use_air
26
+ @application_tag = 'WindowedApplication'
27
+ else
28
+ @application_tag = 'Application'
29
+ end
30
+
31
+ @component_names = []
32
+ if File.exists?("app/flex/#{base_folder}/components/generated")
33
+ @component_names = list_mxml_files("app/flex/#{base_folder}/components/generated")
34
+ end
35
+
36
+ @controller_names = []
37
+ if options[:gae] && File.exists?("app/controllers")
38
+ @use_gae = true
39
+ @controller_names =
40
+ Dir.entries("app/controllers").grep(/\.py$/).delete_if { |name| name == "__init__.py" || name == "restful.py" }.map { |name| name.sub(/\.py$/, "") }
41
+ end
42
+ end
43
+
44
+ def manifest
45
+ record do |m|
46
+ m.template 'mainapp.mxml', File.join('app', 'flex', "#{project_name}.mxml")
47
+ if options[:gae]
48
+ m.template 'main.py.erb', 'main.py'
49
+ end
50
+ end
51
+ end
52
+
53
+ protected
54
+ def add_options!(opt)
55
+ opt.separator ''
56
+ opt.separator 'Options:'
57
+ opt.on("--gae", "Generate Google App Engine Python classes in addition to RestfulX Flex resources.",
58
+ "Default: false") { |v| options[:gae] = v }
59
+ end
60
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env python
2
+
3
+ import logging
4
+ import wsgiref.handlers
5
+
6
+ from google.appengine.api import users
7
+ from google.appengine.ext import webapp
8
+ from google.appengine.ext.webapp.util import run_wsgi_app
9
+ from app.controllers import <%= controller_names.join(", ") %>
10
+
11
+ class AppController(webapp.RequestHandler):
12
+ def get(self):
13
+ self.redirect("/public/index.html")
14
+
15
+ def main():
16
+ application = webapp.WSGIApplication(
17
+ [('/*$', AppController),
18
+ <% for component in controller_names -%>
19
+ <% if component == controller_names.last -%>
20
+ ('/<%= component %>.*', <%= component %>.Controller)
21
+ <% else -%>
22
+ ('/<%= component %>.*', <%= component %>.Controller),
23
+ <% end -%>
24
+ <% end -%>
25
+ ], debug=True)
26
+ wsgiref.handlers.CGIHandler().run(application)
27
+
28
+ if __name__ == '__main__':
29
+ main()
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <mx:<%= application_tag %> xmlns:mx="http://www.adobe.com/2006/mxml"
3
+ xmlns:generated="<%= base_package %>.components.generated.*"
4
+ paddingBottom="8" paddingLeft="8" paddingRight="8" paddingTop="8"
5
+ layout="horizontal" styleName="plain" initialize="init()">
6
+ <mx:Script>
7
+ <![CDATA[
8
+ <% if use_air -%>
9
+ import org.restfulx.services.air.AIRServiceProvider;
10
+ <% end -%>
11
+ <% if use_gae -%>
12
+ import org.restfulx.services.http.GAEHTTPServiceProvider;
13
+ <% end -%>
14
+ import <%= base_package %>.controllers.<%= command_controller_name %>;
15
+
16
+ private function init():void {
17
+ <% if use_air -%>
18
+ <%= command_controller_name %>.initialize([AIRServiceProvider], AIRServiceProvider.ID, "<%= base_package %>");
19
+ <% elsif use_gae -%>
20
+ <%= command_controller_name %>.initialize([GAEHTTPServiceProvider], GAEHTTPServiceProvider.ID);
21
+ <% else -%>
22
+ <%= command_controller_name %>.initialize();
23
+ <% end -%>
24
+ }
25
+ ]]>
26
+ </mx:Script>
27
+ <mx:LinkBar dataProvider="{mainViewStack}" direction="vertical" borderStyle="solid" backgroundColor="#EEEEEE"/>
28
+ <mx:ViewStack id="mainViewStack" width="100%" height="100%">
29
+ <!-- For a simple demo, put all the components here. -->
30
+ <% for component in component_names -%>
31
+ <generated:<%= component %>/>
32
+ <% end -%>
33
+ </mx:ViewStack>
34
+ </mx:<%= application_tag %>>
35
+
@@ -0,0 +1,29 @@
1
+ Description:
2
+ Scaffolds an entire RestfulX resource. The resource is ready to use as a
3
+ starting point for your restful, resource-oriented application.
4
+
5
+ rx_scaffold :
6
+ 1. Generates all required Flex code.
7
+ 2. You can pass special belongs_to, has_one and has_many attributes
8
+ to generate appropriate relationships.
9
+
10
+ Pass the name of the model, either CamelCased or under_scored, as the first
11
+ argument, and an optional list of attribute pairs.
12
+
13
+ Attribute pairs are column_name:sql_type arguments specifying the
14
+ model's attributes. Timestamps are added by default, so you don't have to
15
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
16
+
17
+ The syntax for belongs_to, has_one and has_many attributes is as follows:
18
+ belongs_to:<relationship_name> or
19
+ belongs_to:<relationship_name>,<another_relationship>,<and_another>
20
+
21
+ You don't have to think up every attribute up front, but it helps to
22
+ sketch out a few so you can start working with the resource immediately.
23
+
24
+ For example, `rx_scaffold post title:string body:text published:boolean`
25
+ gives you a model with those three attributes.
26
+
27
+ Examples:
28
+ `./script/generate rx_scaffold project name:string has_many:tasks`
29
+ `./script/generate rx_scaffold task name:string belongs_to:project`
@@ -0,0 +1,146 @@
1
+ module RestfulX
2
+ module Generator
3
+ class GeneratedAttribute
4
+ attr_accessor :name, :type, :flex_name
5
+
6
+ def initialize(name, type)
7
+ @name, @type = name, type.to_sym
8
+ @flex_name = name.camelcase(:lower)
9
+ end
10
+
11
+ def flex_type
12
+ @flex_type = case type
13
+ when :integer then 'int'
14
+ when :date, :datetime, :time then 'Date'
15
+ when :boolean then 'Boolean'
16
+ when :float, :decimal then 'Number'
17
+ else
18
+ 'String'
19
+ end
20
+ end
21
+
22
+ def flex_default
23
+ @flex_default = case type
24
+ when :integer then '0'
25
+ when :date, :datetime, :time then 'new Date'
26
+ when :boolean then 'false'
27
+ when :float, :decimal then 'new Number'
28
+ else
29
+ "\"\""
30
+ end
31
+ end
32
+
33
+ def gae_type
34
+ @gae_type = case type
35
+ when :integer then 'IntegerProperty'
36
+ when :date then 'DateProperty'
37
+ when :time then 'TimeProperty'
38
+ when :datetime then 'DateTimeProperty'
39
+ when :boolean then 'BooleanProperty'
40
+ when :text then 'TextProperty'
41
+ when :float, :decimal then 'FloatProperty'
42
+ else
43
+ 'StringProperty'
44
+ end
45
+ end
46
+
47
+ def gae_default
48
+ @gae_default = case type
49
+ when :integer then 'default = 0'
50
+ when :date, :time, :datetime then 'auto_now_add = True'
51
+ when :boolean then 'default = False'
52
+ when :float, :decimal then 'default = 0.0'
53
+ else
54
+ ""
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ class RxScaffoldGenerator < RubiGen::Base
62
+ include RestfulX::Configuration
63
+
64
+ attr_reader :project_name,
65
+ :flex_project_name,
66
+ :base_package,
67
+ :base_folder,
68
+ :command_controller_name
69
+
70
+ attr_reader :belongs_tos,
71
+ :has_manies,
72
+ :has_ones
73
+
74
+ attr_reader :name,
75
+ :class_name,
76
+ :file_name
77
+
78
+ def initialize(runtime_args, runtime_options = {})
79
+ super
80
+
81
+ # Name argument is required.
82
+ usage if runtime_args.empty?
83
+
84
+ @args = runtime_args.dup
85
+ @name = @args.shift
86
+ @file_name = @name.underscore
87
+ @class_name = @name.camelize
88
+
89
+ @project_name, @flex_project_name, @command_controller_name,
90
+ @base_package, @base_folder = extract_names
91
+ extract_relationships
92
+ end
93
+
94
+ def manifest
95
+ record do |m|
96
+ m.template 'model.as.erb',
97
+ File.join("app", 'flex', base_folder, "models", "#{@class_name}.as"),
98
+ :assigns => { :resource_controller_name => "#{file_name.pluralize}" }
99
+
100
+ m.template 'component.mxml.erb',
101
+ File.join("app", 'flex', base_folder, "components", "generated", "#{@class_name}Box.mxml"),
102
+ :assigns => { :resource_controller_name => "#{file_name.pluralize}" }
103
+
104
+ if options[:gae]
105
+ m.template 'controller.py.erb', "app/controllers/#{file_name.pluralize}.py"
106
+ m.template 'model.py.erb', "app/models/#{file_name}.py"
107
+ end
108
+
109
+ m.dependency 'rx_controller', [name] + @args, :collision => :force, :gae => options[:gae]
110
+ end
111
+ end
112
+
113
+ protected
114
+ def extract_relationships
115
+ @belongs_tos = []
116
+ @has_ones = []
117
+ @has_manies = []
118
+ # Figure out has_one, has_many and belongs_to based on args
119
+ @args.each do |arg|
120
+ if arg =~ /^has_one:/
121
+ # arg = "has_one:arg1,arg2", so all the has_one are together
122
+ @has_ones = arg.split(':')[1].split(',')
123
+ elsif arg =~ /^has_many:/
124
+ # arg = "has_many:arg1,arg2", so all the has_many are together
125
+ @has_manies = arg.split(":")[1].split(",")
126
+ elsif arg =~ /^belongs_to:/ # belongs_to:arg1,arg2
127
+ @belongs_tos = arg.split(":")[1].split(',')
128
+ end
129
+ end
130
+
131
+ @args.delete_if { |elt| elt =~ /^(has_one|has_many|belongs_to):/ }
132
+ end
133
+
134
+ def attributes
135
+ @attributes ||= @args.collect do |attribute|
136
+ RestfulX::Generator::GeneratedAttribute.new(*attribute.split(":"))
137
+ end
138
+ end
139
+
140
+ def add_options!(opt)
141
+ opt.separator ''
142
+ opt.separator 'Options:'
143
+ opt.on("--gae", "Generate Google App Engine Python classes in addition to RestfulX Flex resources.",
144
+ "Default: false") { |v| options[:gae] = v }
145
+ end
146
+ end
@@ -0,0 +1,149 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" label="<%= class_name %>"
3
+ xmlns:rcomponents="org.restfulx.components.*">
4
+ <mx:Script><![CDATA[
5
+ import org.restfulx.Rx;
6
+ import org.restfulx.utils.RxUtils;
7
+ import <%= base_package %>.models.<%= class_name %>;
8
+ <% for model in belongs_tos -%>
9
+ import <%= base_package %>.models.<%= model.camelcase %>;
10
+ <% end -%>
11
+
12
+ [Bindable]
13
+ private var _<%= class_name.dcfirst %>:<%= class_name %> = new <%= class_name %>();
14
+
15
+ private function new<%= class_name %>():void {
16
+ _<%= class_name.dcfirst %> = new <%= class_name %>();
17
+ <%= class_name.dcfirst.pluralize %>List.selectedIndex = -1;
18
+ }
19
+
20
+ private function save<%= class_name %>():void {
21
+ if (_<%= class_name.dcfirst %>.id) {
22
+ update<%= class_name %>();
23
+ } else {
24
+ create<%= class_name %>();
25
+ }
26
+ }
27
+
28
+ private function create<%= class_name %>():void {
29
+ var <%= class_name.dcfirst %>:<%= class_name %> = new <%= class_name %>();
30
+ <% for attribute in attributes -%>
31
+ <% if attribute.type == :boolean -%>
32
+ <%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>CheckBox.selected;
33
+ <% elsif attribute.type == :string -%>
34
+ <%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>TextInput.text;
35
+ <% elsif attribute.type == :text -%>
36
+ <%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>TextArea.text;
37
+ <% elsif attribute.type == :datetime || attribute.type == :time -%>
38
+ <%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>DateTimeTextInput.date;
39
+ <% elsif attribute.type == :date -%>
40
+ <%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>DateField.selectedDate;
41
+ <% else -%>
42
+ <%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_type %>(<%= attribute.flex_name %>TextInput.text);
43
+ <% end -%>
44
+ <% end -%>
45
+
46
+ <% for model in belongs_tos -%>
47
+ <%= class_name.dcfirst %>.<%= model.camelcase(:lower) %> = <%= model.camelcase %>(<%= model.camelcase(:lower) %>ComboBox.selectedItem);
48
+ <% end -%>
49
+ <%= class_name.dcfirst %>.create({onSuccess: on<%= class_name %>Create});
50
+ }
51
+
52
+ private function update<%= class_name %>():void {
53
+ <% for attribute in attributes -%>
54
+ <% if attribute.type == :boolean -%>
55
+ _<%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>CheckBox.selected;
56
+ <% elsif attribute.type == :string -%>
57
+ _<%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>TextInput.text;
58
+ <% elsif attribute.type == :text -%>
59
+ _<%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>TextArea.text;
60
+ <% elsif attribute.type == :datetime || attribute.type == :time -%>
61
+ _<%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>DateTimeTextInput.date;
62
+ <% elsif attribute.type == :date -%>
63
+ _<%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_name %>DateField.selectedDate;
64
+ <% else -%>
65
+ _<%= class_name.dcfirst %>.<%= attribute.flex_name %> = <%= attribute.flex_type %>(<%= attribute.flex_name %>TextInput.text);
66
+ <% end -%>
67
+ <% end -%>
68
+
69
+ <% for model in belongs_tos -%>
70
+ _<%= class_name.dcfirst %>.<%= model.camelcase(:lower) %> = <%= model.camelcase %>(<%= model.camelcase(:lower) %>ComboBox.selectedItem);
71
+ <% end -%>
72
+ _<%= class_name.dcfirst %>.update({onSuccess: on<%= class_name %>Update});
73
+ }
74
+
75
+ private function destroy<%= class_name %>():void {
76
+ _<%= class_name.dcfirst %>.destroy({onSuccess: on<%= class_name %>Destroy});
77
+ }
78
+
79
+ private function on<%= class_name %>Select():void {
80
+ _<%= class_name.dcfirst %> = RxUtils.clone(<%= class_name.dcfirst.pluralize %>List.selectedItem) as <%= class_name %>;
81
+ }
82
+
83
+ private function on<%= class_name %>Create(<%= class_name.dcfirst %>:<%= class_name %>):void {
84
+ _<%= class_name.dcfirst %> = new <%= class_name %>;
85
+ }
86
+
87
+ private function on<%= class_name %>Update(<%= class_name.dcfirst %>:<%= class_name %>):void {
88
+ <%= class_name.dcfirst.pluralize %>List.selectedItem = <%= class_name.dcfirst %>;
89
+ _<%= class_name.dcfirst %> = RxUtils.clone(<%= class_name.dcfirst %>) as <%= class_name %>;
90
+ }
91
+
92
+ private function on<%= class_name %>Destroy(<%= class_name.dcfirst %>:<%= class_name %>):void {
93
+ on<%= class_name %>Create(<%= class_name.dcfirst %>);
94
+ }
95
+
96
+ private function canDelete<%= class_name %>(<%= class_name.dcfirst %>:<%= class_name %>):Boolean {
97
+ return <%= class_name.dcfirst %> != null && !RxUtils.isEmpty(<%= class_name.dcfirst %>.id);
98
+ }
99
+ ]]></mx:Script>
100
+ <mx:Panel id="<%= class_name.dcfirst.pluralize %>Panel"
101
+ title="<%= class_name.pluralize %>" cornerRadius="0" dropShadowEnabled="false" borderStyle="solid"
102
+ borderThickness="1" backgroundColor="#EEEEEE" width="25%" height="100%">
103
+ <mx:List id="<%= class_name.dcfirst.pluralize %>List"
104
+ width="100%" height="100%"
105
+ dataProvider="{Rx.models.index(<%= class_name %>)}"
106
+ change="on<%= class_name %>Select()"/>
107
+ <mx:ControlBar width="100%">
108
+ <mx:Button label="New <%= class_name %>" width="100%" height="30"
109
+ click="new<%= class_name %>()"/>
110
+ </mx:ControlBar>
111
+ </mx:Panel>
112
+ <mx:Panel title="Edit <%= class_name %>" cornerRadius="0" dropShadowEnabled="false" borderStyle="solid"
113
+ borderThickness="1" backgroundColor="#EEEEEE" width="75%" height="100%">
114
+ <mx:Form width="100%" height="100%">
115
+ <% for attribute in attributes -%>
116
+ <mx:FormItem label="<%= attribute.flex_name.ucfirst %>" width="100%">
117
+ <% if attribute.type == :boolean -%>
118
+ <mx:CheckBox id="<%= attribute.flex_name %>CheckBox" selected="{_<%= class_name.dcfirst %>.<%= attribute.flex_name %>}"/>
119
+ <% elsif attribute.type == :string -%>
120
+ <mx:TextInput id="<%= attribute.flex_name %>TextInput" width="100%" text="{_<%= class_name.dcfirst %>.<%= attribute.flex_name %>}"/>
121
+ <% elsif attribute.type == :text -%>
122
+ <mx:TextArea id="<%= attribute.flex_name %>TextArea" width="100%" height="200" text="{_<%= class_name.dcfirst %>.<%= attribute.flex_name %>}"/>
123
+ <% elsif attribute.type == :datetime || attribute.type == :time -%>
124
+ <rcomponents:DateTimeTextInput id="<%= attribute.flex_name %>DateTimeTextInput" width="200" date="{_<%= class_name.dcfirst %>.<%= attribute.flex_name %>}"/>
125
+ <% elsif attribute.type == :date -%>
126
+ <mx:DateField id="<%= attribute.flex_name %>DateField" selectedDate="{_<%= class_name.dcfirst %>.<%= attribute.flex_name %>}"/>
127
+ <% else -%>
128
+ <mx:TextInput id="<%= attribute.flex_name %>TextInput" width="100%" text="{_<%= class_name.dcfirst %>.<%= attribute.flex_name %>}"/>
129
+ <% end -%>
130
+ </mx:FormItem>
131
+ <% end -%>
132
+ <% for model in belongs_tos -%>
133
+ <mx:FormItem label="<%= model.camelcase %>" width="100%">
134
+ <mx:ComboBox id="<%= model.camelcase(:lower) %>ComboBox" width="200"
135
+ labelField="{<%= model.camelcase %>.LABEL}"
136
+ dataProvider="{Rx.models.index(<%= model.camelcase %>)}" prompt="<%= model.camelcase %> ..."
137
+ selectedItem="{_<%= class_name.dcfirst %>.<%= model.camelcase(:lower) %>}" />
138
+ </mx:FormItem>
139
+ <% end -%>
140
+ </mx:Form>
141
+ <mx:ControlBar width="100%">
142
+ <mx:Button label="Save <%= class_name %>" width="50%" height="30"
143
+ click="save<%= class_name %>()"/>
144
+ <mx:Button label="Delete <%= class_name %>" width="50%" height="30"
145
+ enabled="{canDelete<%= class_name %>(_<%= class_name.dcfirst %>)}"
146
+ click="destroy<%= class_name %>()"/>
147
+ </mx:ControlBar>
148
+ </mx:Panel>
149
+ </mx:HBox>
@@ -0,0 +1,27 @@
1
+ import restful
2
+ import logging
3
+
4
+ from google.appengine.ext import webapp
5
+ from google.appengine.api import users
6
+ from google.appengine.ext import db
7
+ from app.models import assist, <%= file_name %>
8
+
9
+ class Controller(restful.Controller):
10
+ def get(self):
11
+ restful.send_successful_response(self, assist.all(<%= file_name %>.<%= class_name %>))
12
+
13
+ @restful.methods_via_query_allowed
14
+ def post(self):
15
+ model = <%= file_name %>.<%= class_name %>()
16
+ assist.update_model_from_params(model, self.request.params)
17
+ restful.send_successful_response(self, model.to_xml())
18
+
19
+ def put(self):
20
+ model = <%= file_name %>.<%= class_name %>.get_or_insert(db.Key(restful.get_model_key(self)))
21
+ assist.update_model_from_params(model, self.request.params)
22
+ restful.send_successful_response(self, model.to_xml())
23
+
24
+ def delete(self):
25
+ model = <%= file_name %>.<%= class_name %>.get(db.Key(restful.get_model_key(self)))
26
+ db.delete(model)
27
+ restful.send_successful_response(self, model.to_xml())