dima-ruboss4ruby 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/History.txt +2 -2
  2. data/Manifest.txt +9 -3
  3. data/README.rdoc +43 -15
  4. data/Rakefile +9 -4
  5. data/app_generators/ruboss_app/USAGE +11 -2
  6. data/app_generators/ruboss_app/ruboss_app_generator.rb +21 -15
  7. data/app_generators/ruboss_app/templates/app.yaml.erb +12 -0
  8. data/app_generators/ruboss_app/templates/default_tasks.rake +1 -1
  9. data/app_generators/ruboss_app/templates/empty.txt +0 -0
  10. data/app_generators/ruboss_app/templates/generate.rb +1 -5
  11. data/app_generators/ruboss_app/templates/index.yaml +11 -0
  12. data/app_generators/ruboss_app/templates/mainair-app.xml +1 -1
  13. data/bin/ruboss-gen +18 -4
  14. data/generators/ruboss_config/ruboss_config_generator.rb +0 -5
  15. data/generators/ruboss_controller/ruboss_controller_generator.rb +15 -10
  16. data/generators/ruboss_controller/templates/assist.py +65 -0
  17. data/generators/ruboss_controller/templates/restful.py +136 -0
  18. data/generators/ruboss_main_app/ruboss_main_app_generator.rb +18 -4
  19. data/generators/ruboss_main_app/templates/main.py.erb +29 -0
  20. data/generators/ruboss_main_app/templates/mainapp.mxml +5 -1
  21. data/generators/ruboss_scaffold/ruboss_scaffold_generator.rb +77 -46
  22. data/generators/ruboss_scaffold/templates/controller.py.erb +27 -0
  23. data/generators/ruboss_scaffold/templates/model.as.erb +1 -1
  24. data/generators/ruboss_scaffold/templates/model.py.erb +14 -0
  25. data/generators/ruboss_yaml_scaffold/USAGE +42 -4
  26. data/generators/ruboss_yaml_scaffold/ruboss_yaml_scaffold_generator.rb +8 -4
  27. data/lib/ruboss4ruby.rb +15 -2
  28. data/lib/ruboss4ruby/active_foo.rb +32 -3
  29. data/lib/ruboss4ruby/active_record_default_methods.rb +19 -7
  30. data/lib/ruboss4ruby/active_record_tasks.rb +9 -3
  31. data/lib/ruboss4ruby/configuration.rb +32 -0
  32. data/lib/ruboss4ruby/datamapper_foo.rb +6 -0
  33. data/lib/ruboss4ruby/rails/recipes.rb +5 -3
  34. data/lib/ruboss4ruby/rails/swf_helper.rb +1 -0
  35. data/lib/ruboss4ruby/tasks.rb +5 -0
  36. data/rails_generators/ruboss_config/ruboss_config_generator.rb +14 -13
  37. data/rails_generators/ruboss_config/templates/mainair-app.xml +1 -1
  38. data/rails_generators/ruboss_config/templates/ruboss_tasks.rake +1 -0
  39. data/rails_generators/ruboss_controller/ruboss_controller_generator.rb +2 -5
  40. data/rails_generators/ruboss_scaffold/ruboss_scaffold_generator.rb +66 -62
  41. data/rails_generators/ruboss_scaffold/templates/model.as.erb +1 -1
  42. data/rails_generators/ruboss_yaml_scaffold/USAGE +38 -1
  43. data/rails_generators/ruboss_yaml_scaffold/ruboss_yaml_scaffold_generator.rb +0 -5
  44. data/rcl-1.0.txt +0 -0
  45. data/rdoc/generators/template/html/jamis.rb +588 -0
  46. data/ruboss4ruby.gemspec +12 -12
  47. metadata +15 -26
@@ -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
@@ -7,9 +7,10 @@ class RubossMainAppGenerator < RubiGen::Base
7
7
  :base_folder,
8
8
  :command_controller_name,
9
9
  :model_names,
10
- :command_names,
11
10
  :component_names,
11
+ :controller_names,
12
12
  :use_air,
13
+ :use_gae,
13
14
  :application_tag
14
15
 
15
16
  def initialize(runtime_args, runtime_options = {})
@@ -31,16 +32,29 @@ class RubossMainAppGenerator < RubiGen::Base
31
32
  if File.exists?("app/flex/#{base_folder}/components/generated")
32
33
  @component_names = list_mxml_files("app/flex/#{base_folder}/components/generated")
33
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
34
42
  end
35
43
 
36
44
  def manifest
37
45
  record do |m|
38
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
39
50
  end
40
51
  end
41
52
 
42
53
  protected
43
- def banner
44
- "Usage: #{$0} #{spec.name}"
45
- end
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 Ruboss Flex resources.",
58
+ "Default: false") { |v| options[:gae] = v }
59
+ end
46
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()
@@ -8,12 +8,16 @@
8
8
  <% if use_air -%>
9
9
  import org.ruboss.services.air.AIRServiceProvider;
10
10
  <% end -%>
11
- import org.ruboss.Ruboss;
11
+ <% if use_gae -%>
12
+ import org.ruboss.services.http.GAEHTTPServiceProvider;
13
+ <% end -%>
12
14
  import <%= base_package %>.controllers.<%= command_controller_name %>;
13
15
 
14
16
  private function init():void {
15
17
  <% if use_air -%>
16
18
  <%= command_controller_name %>.initialize([AIRServiceProvider], AIRServiceProvider.ID, "<%= base_package %>");
19
+ <% elsif use_gae -%>
20
+ <%= command_controller_name %>.initialize([GAEHTTPServiceProvider], GAEHTTPServiceProvider.ID);
17
21
  <% else -%>
18
22
  <%= command_controller_name %>.initialize();
19
23
  <% end -%>
@@ -10,22 +10,48 @@ module Ruboss4Ruby
10
10
 
11
11
  def flex_type
12
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'
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
19
  end
20
20
  end
21
21
 
22
- def flex_default(prefix = '')
22
+ def flex_default
23
23
  @flex_default = case type
24
- when :integer, :float, :decimal then '0'
25
- when :string, :text then '""'
26
- when :boolean then 'false'
27
- else
28
- 'null'
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
+ ""
29
55
  end
30
56
  end
31
57
  end
@@ -48,9 +74,7 @@ class RubossScaffoldGenerator < RubiGen::Base
48
74
  attr_reader :name,
49
75
  :class_name,
50
76
  :file_name
51
-
52
- attr_accessor :constructor_args
53
-
77
+
54
78
  def initialize(runtime_args, runtime_options = {})
55
79
  super
56
80
 
@@ -62,8 +86,34 @@ class RubossScaffoldGenerator < RubiGen::Base
62
86
  @file_name = @name.underscore
63
87
  @class_name = @name.camelize
64
88
 
65
- @project_name, @flex_project_name, @command_controller_name, @base_package, @base_folder = extract_names
66
-
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
+ # Run the rcontroller generator to clobber the
110
+ # RubossCommandController subclass to include the new models.
111
+ m.dependency 'ruboss_controller', [name] + @args, :collision => :force, :gae => options[:gae]
112
+ end
113
+ end
114
+
115
+ protected
116
+ def extract_relationships
67
117
  @belongs_tos = []
68
118
  @has_ones = []
69
119
  @has_manies = []
@@ -80,38 +130,19 @@ class RubossScaffoldGenerator < RubiGen::Base
80
130
  end
81
131
  end
82
132
 
83
- # Remove the has_one and has_many arguments since they are
84
- # not for consumption by the scaffold generator, and since
85
- # we have already used them to set the @belongs_tos, @has_ones and
86
- # @has_manies.
87
133
  @args.delete_if { |elt| elt =~ /^(has_one|has_many|belongs_to):/ }
88
134
  end
89
-
90
- def manifest
91
- record do |m|
92
- # Generate Flex AS model and MXML component based on the
93
- # Ruboss templates.
94
-
95
- puts @file_name
96
-
97
- m.template 'model.as.erb',
98
- File.join("app", 'flex', base_folder, "models", "#{@class_name}.as"),
99
- :assigns => { :resource_controller_name => "#{file_name.pluralize}" }
100
135
 
101
- m.template 'component.mxml.erb',
102
- File.join("app", 'flex', base_folder, "components", "generated", "#{@class_name}Box.mxml"),
103
- :assigns => { :resource_controller_name => "#{file_name.pluralize}" }
104
-
105
- # Run the rcontroller generator to clobber the
106
- # RubossCommandController subclass to include the new models.
107
- m.dependency 'ruboss_controller', [name] + @args, :collision => :force
136
+ def attributes
137
+ @attributes ||= @args.collect do |attribute|
138
+ Ruboss4Ruby::Generator::GeneratedAttribute.new(*attribute.split(":"))
108
139
  end
109
140
  end
110
-
111
- protected
112
- def attributes
113
- @attributes ||= @args.collect do |attribute|
114
- Ruboss4Ruby::Generator::GeneratedAttribute.new(*attribute.split(":"))
115
- end
116
- end
141
+
142
+ def add_options!(opt)
143
+ opt.separator ''
144
+ opt.separator 'Options:'
145
+ opt.on("--gae", "Generate Google App Engine Python classes in addition to Ruboss Flex resources.",
146
+ "Default: false") { |v| options[:gae] = v }
147
+ end
117
148
  end
@@ -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(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())
@@ -17,7 +17,7 @@ package <%= base_package %>.models {
17
17
  <% if attribute.type == :datetime || attribute.type == :time -%>
18
18
  [DateTime]
19
19
  <% end -%>
20
- public var <%= attribute.flex_name %>:<%= attribute.flex_type %>;
20
+ public var <%= attribute.flex_name %>:<%= attribute.flex_type %> = <%= attribute.flex_default %>;
21
21
 
22
22
  <% end -%>
23
23
  <% for model in belongs_tos -%>
@@ -0,0 +1,14 @@
1
+ from google.appengine.ext import db
2
+ <% if belongs_tos.length > 0 -%>
3
+ import <%= belongs_tos.join(", ") %>
4
+ <% end -%>
5
+
6
+ class <%= class_name %>(db.Model):
7
+ <% for attribute in attributes -%>
8
+ <%= attribute.name %> = db.<%= attribute.gae_type %>(<%= attribute.gae_default %>)
9
+ <% end -%>
10
+ <% for model in belongs_tos -%>
11
+ <%= model %> = db.ReferenceProperty(<%= model %>.<%= model.camelcase %>)
12
+ <% end -%>
13
+
14
+
@@ -1,7 +1,45 @@
1
1
  Description:
2
- Scaffolds an entire application based on db/model.yml file. This generator
3
- transforms entries in db/model.yml into command line calls to
4
- "ruboss_scaffold".
2
+ Scaffolds an entire application based on db/model.yml file.
3
+
4
+ This generator transforms entries in db/model.yml into
5
+ command line calls to "ruboss_scaffold".
5
6
 
6
7
  Examples:
7
- `./script/generate ruboss_yaml_scaffold`
8
+ `./script/generate ruboss_yaml_scaffold`
9
+
10
+ Sample Model File:
11
+ project:
12
+ - name: string
13
+ - notes: text
14
+ - start_date: date
15
+ - end_date: date
16
+ - completed: boolean
17
+ - belongs_to: [user]
18
+ - has_many: [tasks]
19
+
20
+ location:
21
+ - name: string
22
+ - notes: text
23
+ - belongs_to: [user]
24
+ - has_many: [tasks]
25
+
26
+ task:
27
+ - name: string
28
+ - notes: text
29
+ - start_time: datetime
30
+ - end_time: datetime
31
+ - completed: boolean
32
+ - next_action: boolean
33
+ - belongs_to: [project, location, user]
34
+
35
+ note:
36
+ - content: text
37
+ - belongs_to: [user]
38
+
39
+ user:
40
+ - login: string
41
+ - first_name: string
42
+ - last_name: string
43
+ - email: string
44
+ - has_many: [tasks, projects, locations]
45
+ - has_one: [note]