dima-restfulx 1.2.2 → 1.2.3
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.
- data/README.rdoc +1 -1
- data/Rakefile +4 -2
- data/VERSION.yml +1 -1
- data/app_generators/rx_app/rx_app_generator.rb +2 -2
- data/app_generators/rx_app/templates/actionscript.properties +1 -1
- data/app_generators/rx_app/templates/actionscriptair.properties +1 -1
- data/app_generators/rx_app/templates/mainapp-config.xml +1 -0
- data/app_generators/rx_app/templates/mainapp.mxml +19 -3
- data/app_generators/rx_app/templates/restfulx.yml +9 -24
- data/bin/rx-gen +1 -1
- data/lib/restfulx/active_foo.rb +5 -3
- data/lib/restfulx/active_record_tasks.rb +1 -2
- data/lib/restfulx/active_record_uuid_helper.rb +17 -0
- data/lib/restfulx/configuration.rb +20 -26
- data/lib/restfulx/{schema_to_yaml → rails/schema_to_yaml}/extensions/enumerable.rb +1 -0
- data/lib/restfulx/{schema_to_yaml → rails/schema_to_yaml}/settings/config.rb +1 -0
- data/lib/restfulx/{schema_to_yaml → rails/schema_to_yaml}/settings/core.rb +4 -1
- data/lib/restfulx/{schema_to_yaml.rb → rails/schema_to_yaml.rb} +2 -12
- data/lib/restfulx/rails/swf_helper.rb +7 -8
- data/lib/restfulx/tasks.rb +0 -1
- data/lib/restfulx.rb +2 -10
- data/rails_generators/rx_config/rx_config_generator.rb +20 -9
- data/rails_generators/rx_config/templates/actionscript.properties +1 -1
- data/rails_generators/rx_config/templates/actionscriptair.properties +1 -1
- data/rails_generators/rx_config/templates/mainapp-config.xml +1 -0
- data/rails_generators/rx_config/templates/restfulx.erb +46 -10
- data/rails_generators/rx_config/templates/restfulx.yml +9 -5
- data/rails_generators/rx_config/templates/session_store_flash.erb +1 -0
- data/rails_generators/rx_main_app/rx_main_app_generator.rb +2 -2
- data/rails_generators/rx_main_app/templates/mainapp.mxml +1 -1
- data/rails_generators/rx_scaffold/rx_scaffold_generator.rb +16 -7
- data/rails_generators/rx_scaffold/templates/controllers/resource_controller.rb.erb +2 -2
- data/rails_generators/rx_scaffold/templates/functional_test.rb +45 -0
- data/rails_generators/rx_scaffold/templates/helper_test.rb +4 -0
- data/rails_generators/rx_scaffold/templates/layouts/default.erb +7 -5
- data/rails_generators/rx_scaffold/templates/migration.rb.erb +4 -4
- data/rxgen_generators/rx_config/rx_config_generator.rb +2 -0
- data/rxgen_generators/rx_controller/rx_controller_generator.rb +1 -0
- data/rxgen_generators/rx_controller/templates/assist.py +4 -4
- data/rxgen_generators/rx_controller/templates/iso8601.py +92 -0
- data/rxgen_generators/rx_main_app/rx_main_app_generator.rb +2 -2
- data/rxgen_generators/rx_main_app/templates/mainapp.mxml +19 -3
- data/rxgen_generators/rx_scaffold/rx_scaffold_generator.rb +57 -10
- data/rxgen_generators/rx_scaffold/templates/{component.mxml.erb → layouts/default.erb} +56 -10
- data/rxgen_generators/rx_scaffold/templates/model.as.erb +33 -2
- data/spec/restfulx_spec.rb +1 -4
- data/spec/spec_helper.rb +0 -3
- data/tasks/restfulx.rake +2 -0
- data/test/rails/helpers/functional_test_helper.rb +1 -1
- data/test/rails/helpers/test_helper.rb +1 -8
- data/test/rails/helpers/unit_test_helper.rb +2 -3
- data/test/rails/test_active_foo.rb +1 -1
- data/test/rails/test_rails_integration_functional.rb +1 -1
- data/test/rails/test_to_fxml.rb +1 -1
- data/test/rails/test_to_json.rb +1 -1
- metadata +60 -75
- data/lib/restfulx/uuid_helper.rb +0 -15
- /data/test/rails/controllers/{application.rb → application_controller.rb} +0 -0
@@ -1,12 +1,47 @@
|
|
1
|
-
#
|
2
|
-
# which
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
# the following patches allow us to overwrite session key on file uploads from Flash,
|
2
|
+
# which ends up creating a new session for every File.upload() invocation.
|
3
|
+
|
4
|
+
<% if RAILS_GEM_VERSION =~ /^2.3/ -%>
|
5
|
+
require 'rack/utils'
|
6
|
+
|
7
|
+
class FlashSessionCookieMiddleware
|
8
|
+
def initialize(app, session_key = '_session_id')
|
9
|
+
@app = app
|
10
|
+
@session_key = session_key
|
11
|
+
@session_token = "_session_id"
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
|
16
|
+
params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
|
17
|
+
env['HTTP_COOKIE'] = [ @session_key, params[@session_token] ].join('=').freeze unless params[@session_token].nil?
|
18
|
+
end
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class FlexNestedAttributeMiddleware
|
24
|
+
def initialize(app)
|
25
|
+
@app = app
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(env)
|
29
|
+
req = Rack::Request.new(env)
|
30
|
+
if req && req.path_info =~ /\.fxml$/
|
31
|
+
if req.put? || req.post? || req.delete?
|
32
|
+
req.params.each do |key,value|
|
33
|
+
value.select { |k,v| k =~ /\_attributes$/ }.each do |match|
|
34
|
+
env['rack.request.form_hash'][key][match[0]] = ActiveSupport::JSON.decode(match[1])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@app.call(env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
ActionController::Dispatcher.middleware.insert_after 'ActionController::ParamsParser', FlexNestedAttributeMiddleware
|
44
|
+
<% else -%>
|
10
45
|
class CGI::Session
|
11
46
|
alias original_initialize initialize
|
12
47
|
|
@@ -27,6 +62,7 @@ class CGI::Session
|
|
27
62
|
return option
|
28
63
|
end
|
29
64
|
end
|
65
|
+
<% end -%>
|
30
66
|
|
31
67
|
# If you have configured your Rails/Flex/AIR application to share authenticity_token
|
32
68
|
# comment this out to enable forgery protection. By default, this is disabled to allow
|
@@ -35,5 +71,5 @@ ActionController::Base.allow_forgery_protection = false
|
|
35
71
|
|
36
72
|
<% if distributed -%>
|
37
73
|
# If we are in distributed mode we need to make sure that the RestfulX::UUIDHelper is loaded
|
38
|
-
require "restfulx/
|
74
|
+
require "restfulx/active_record_uuid_helper"
|
39
75
|
<% end -%>
|
@@ -2,22 +2,22 @@
|
|
2
2
|
|
3
3
|
# This option controls what the main Flex application file will be called.
|
4
4
|
# By default it will be equal to the name of your rails project camelized
|
5
|
-
|
5
|
+
project_name: <%= project_name %>
|
6
6
|
|
7
7
|
# This options determines what the root folder for generated Flex code is.
|
8
8
|
# By default 'app/flex'
|
9
|
-
|
9
|
+
flex_root: <%= flex_root %>
|
10
10
|
|
11
11
|
# By default flex models, commands, controllers and components are genearated into
|
12
12
|
# <flex-root>/<your rails project name> folder. If you'd like to customize the target folder
|
13
13
|
# (to say append a "com" package before your rails project name) uncomment the line below
|
14
14
|
# base-package must follow the usual flex package notation (a string separated by ".")
|
15
|
-
|
15
|
+
base_package: <%= base_package %>
|
16
16
|
|
17
17
|
# Main RestfulX controller is typically named AppicationController. This controller is created in
|
18
18
|
# <base-package>.controllers folder. You can customize the name by uncommenting the following line
|
19
19
|
# and changing the controller name.
|
20
|
-
|
20
|
+
controller_name: <%= command_controller_name %>
|
21
21
|
|
22
22
|
# If you are using Rails on the back-end and Adobe AIR as the client you can generate Rails/Flex/AIR
|
23
23
|
# code to take advantage of synchronization (online/offline) support in RestfulX by changing the following
|
@@ -35,17 +35,21 @@ defaults: &defaults
|
|
35
35
|
tables: [table1 table2]
|
36
36
|
fields: [field1 field2]
|
37
37
|
|
38
|
+
# set up specific options for development environment
|
38
39
|
development:
|
39
40
|
<<: *defaults
|
40
41
|
|
42
|
+
# set up specific options for test environment
|
41
43
|
test:
|
42
44
|
<<: *defaults
|
43
45
|
|
46
|
+
# set up specific options for production environment
|
44
47
|
production:
|
45
48
|
<<: *defaults
|
46
49
|
|
47
|
-
#
|
50
|
+
# The following special model.yml fields are supported.
|
48
51
|
#
|
52
|
+
# For example:
|
49
53
|
# attachment_field: [avatar]
|
50
54
|
# * arg takes Paperclip field name, or takes [uploaded_data] for Attachment_Fu
|
51
55
|
# belongs_to: [account, profile]
|
@@ -0,0 +1 @@
|
|
1
|
+
ActionController::Dispatcher.middleware.use FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]
|
@@ -43,8 +43,8 @@ class RxMainAppGenerator < Rails::Generator::Base
|
|
43
43
|
end
|
44
44
|
|
45
45
|
@component_names = []
|
46
|
-
if File.exists?("#{flex_root}/#{base_folder}/
|
47
|
-
@component_names = list_mxml_files("#{flex_root}/#{base_folder}/
|
46
|
+
if File.exists?("#{flex_root}/#{base_folder}/views/generated")
|
47
|
+
@component_names = list_mxml_files("#{flex_root}/#{base_folder}/views/generated")
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
2
2
|
<mx:<%= application_tag %> xmlns:mx="http://www.adobe.com/2006/mxml"
|
3
|
-
xmlns:generated="<%= base_package %>.
|
3
|
+
xmlns:generated="<%= base_package %>.views.generated.*"
|
4
4
|
paddingBottom="8" paddingLeft="8" paddingRight="8" paddingTop="8"
|
5
5
|
layout="horizontal" styleName="plain" initialize="init()">
|
6
6
|
<mx:Script>
|
@@ -125,7 +125,7 @@ class RxScaffoldGenerator < Rails::Generator::NamedBase
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def manifest
|
128
|
-
record do |m|
|
128
|
+
record do |m|
|
129
129
|
unless options[:flex_view_only]
|
130
130
|
m.template 'model.as.erb',
|
131
131
|
File.join("#{@flex_root}", base_folder, "models", "#{@class_name}.as"),
|
@@ -139,11 +139,11 @@ class RxScaffoldGenerator < Rails::Generator::NamedBase
|
|
139
139
|
|
140
140
|
if @layout.size > 0
|
141
141
|
m.template "layouts/#{@layout}.erb",
|
142
|
-
File.join("#{@flex_root}", base_folder, "
|
142
|
+
File.join("#{@flex_root}", base_folder, "views", "generated", "#{@class_name}Box.mxml"),
|
143
143
|
:assigns => { :resource_controller_name => "#{file_name.pluralize}" }
|
144
144
|
else
|
145
145
|
m.template "layouts/#{RxSettings.layouts.default}.erb",
|
146
|
-
File.join("#{@flex_root}", base_folder, "
|
146
|
+
File.join("#{@flex_root}", base_folder, "views", "generated", "#{@class_name}Box.mxml"),
|
147
147
|
:assigns => { :resource_controller_name => "#{file_name.pluralize}" }
|
148
148
|
end
|
149
149
|
|
@@ -155,11 +155,20 @@ class RxScaffoldGenerator < Rails::Generator::NamedBase
|
|
155
155
|
unless options[:skip_migration]
|
156
156
|
FileUtils.rm Dir.glob("db/migrate/[0-9]*_create_#{file_path.gsub(/\//, '_').pluralize}.rb"), :force => true
|
157
157
|
m.migration_template 'migration.rb.erb', 'db/migrate', :assigns => {
|
158
|
-
:migration_name => "Create#{
|
158
|
+
:migration_name => "Create#{file_path.gsub(/\//, '_').pluralize.camelcase.gsub(/::/, '')}"
|
159
159
|
}, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" unless options[:flex_only]
|
160
160
|
end
|
161
|
-
|
162
|
-
m.
|
161
|
+
|
162
|
+
m.directory(File.join('test/functional', controller_class_path))
|
163
|
+
m.directory(File.join('test/unit', class_path))
|
164
|
+
m.directory(File.join('test/unit/helpers', class_path))
|
165
|
+
|
166
|
+
m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
|
167
|
+
m.template('helper_test.rb', File.join('test/unit/helpers', controller_class_path, "#{controller_file_name}_helper_test.rb"))
|
168
|
+
|
169
|
+
if File.open('config/routes.rb').grep(/^\s*map.resources :#{controller_file_name}/).empty?
|
170
|
+
m.route_resources controller_file_name
|
171
|
+
end
|
163
172
|
|
164
173
|
m.dependency 'rx_controller', [name] + @args, :collision => :force
|
165
174
|
end
|
@@ -230,4 +239,4 @@ class RxScaffoldGenerator < Rails::Generator::NamedBase
|
|
230
239
|
opt.on("-fv", "--flex-view-only", "Only generate the Flex component files",
|
231
240
|
"Default: false") { |v| options[:flex_view_only] = v }
|
232
241
|
end
|
233
|
-
end
|
242
|
+
end
|
@@ -10,8 +10,8 @@ class <%= controller_class_name %>Controller < ResourceController::Base
|
|
10
10
|
update.failure.wants.fxml { render :fxml => @object.errors }
|
11
11
|
destroy.wants.fxml { render :fxml => @object }
|
12
12
|
|
13
|
-
private
|
14
|
-
|
13
|
+
private
|
14
|
+
|
15
15
|
def collection
|
16
16
|
@collection = end_of_association_chain.all
|
17
17
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
|
4
|
+
test "should get index" do
|
5
|
+
get :index
|
6
|
+
assert_response :success
|
7
|
+
assert_not_nil assigns(:<%= table_name %>)
|
8
|
+
end
|
9
|
+
|
10
|
+
test "should get new" do
|
11
|
+
get :new
|
12
|
+
assert_response :success
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should create <%= file_name %>" do
|
16
|
+
assert_difference('<%= class_name %>.count') do
|
17
|
+
post :create, :<%= file_name %> => { }
|
18
|
+
end
|
19
|
+
|
20
|
+
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
|
21
|
+
end
|
22
|
+
|
23
|
+
test "should show <%= file_name %>" do
|
24
|
+
get :show, :id => <%= table_name %>(:one).id
|
25
|
+
assert_response :success
|
26
|
+
end
|
27
|
+
|
28
|
+
test "should get edit" do
|
29
|
+
get :edit, :id => <%= table_name %>(:one).id
|
30
|
+
assert_response :success
|
31
|
+
end
|
32
|
+
|
33
|
+
test "should update <%= file_name %>" do
|
34
|
+
put :update, :id => <%= table_name %>(:one).id, :<%= file_name %> => { }
|
35
|
+
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
|
36
|
+
end
|
37
|
+
|
38
|
+
test "should destroy <%= file_name %>" do
|
39
|
+
assert_difference('<%= class_name %>.count', -1) do
|
40
|
+
delete :destroy, :id => <%= table_name %>(:one).id
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_redirected_to <%= table_name %>_path
|
44
|
+
end
|
45
|
+
end
|
@@ -9,12 +9,14 @@
|
|
9
9
|
import <%= base_package %>.models.<%= model.camelcase %>;
|
10
10
|
<% end -%>
|
11
11
|
<% if attachment_field.size > 0 -%>
|
12
|
+
import flash.net.FileReference;
|
12
13
|
import org.restfulx.utils.RxFileReference;
|
13
14
|
<% end -%>
|
14
15
|
|
15
16
|
[Bindable]
|
16
17
|
private var <%= class_name.dcfirst %>:<%= class_name %> = new <%= class_name %>();
|
17
18
|
<% if attachment_field.size > 0 -%>
|
19
|
+
|
18
20
|
[Bindable]
|
19
21
|
private var fileName:String = "None selected";
|
20
22
|
|
@@ -83,10 +85,10 @@
|
|
83
85
|
|
84
86
|
private function chooseFile():void {
|
85
87
|
file = new RxFileReference("<%= attachment_field[0].camelcase(:lower) %>");
|
86
|
-
file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false, 0, true);
|
87
|
-
file.addEventListener(Event.SELECT, selectFile, false, 0, true);
|
88
|
-
file.addEventListener(Event.CANCEL, cancelBrowse, false, 0, true);
|
89
|
-
file.browse();
|
88
|
+
file.reference.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false, 0, true);
|
89
|
+
file.reference.addEventListener(Event.SELECT, selectFile, false, 0, true);
|
90
|
+
file.reference.addEventListener(Event.CANCEL, cancelBrowse, false, 0, true);
|
91
|
+
file.reference.browse();
|
90
92
|
}
|
91
93
|
|
92
94
|
private function selectFile(event:Event):void {
|
@@ -98,7 +100,7 @@
|
|
98
100
|
}
|
99
101
|
|
100
102
|
private function fileSelected(event:Event):void {
|
101
|
-
fileName =
|
103
|
+
fileName = FileReference(event.target).name;
|
102
104
|
}
|
103
105
|
|
104
106
|
private function ioErrorHandler(event:Event):void {
|
@@ -19,10 +19,10 @@ class <%= migration_name %> < ActiveRecord::Migration
|
|
19
19
|
<% if attachment_field.size > 0 -%>
|
20
20
|
<% if RxSettings.attachment_plugin == 'paperclip' -%>
|
21
21
|
# For paperclip
|
22
|
-
t.column
|
23
|
-
t.column
|
24
|
-
t.column
|
25
|
-
t.column
|
22
|
+
t.column :<%= attachment_field[0] %>_file_name, :string
|
23
|
+
t.column :<%= attachment_field[0] %>_content_type, :string
|
24
|
+
t.column :<%= attachment_field[0] %>_file_size, :integer
|
25
|
+
t.column :<%= attachment_field[0] %>_updated_at, :datetime
|
26
26
|
<% elsif RxSettings.attachment_plugin == 'attachment_fu' -%>
|
27
27
|
# For attachment_fu
|
28
28
|
t.column :parent_id, :integer
|
@@ -26,6 +26,7 @@ class RxControllerGenerator < RubiGen::Base
|
|
26
26
|
if options[:gae]
|
27
27
|
m.file 'restful.py', 'app/controllers/restful.py' if !File.exist?('app/controllers/restful.py')
|
28
28
|
m.file 'assist.py', 'app/models/assist.py' if !File.exist?('app/models/assist.py')
|
29
|
+
m.file 'iso8601.py', 'app/models/iso8601.py' if !File.exist?('app/models/iso8601.py')
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -23,11 +23,11 @@
|
|
23
23
|
__author__ = 'Dima Berastau'
|
24
24
|
|
25
25
|
from google.appengine.ext import db
|
26
|
-
import datetime
|
26
|
+
import datetime, iso8601
|
27
27
|
|
28
28
|
# Some useful module methods
|
29
29
|
def all(model):
|
30
|
-
items = "".join(str(item.to_xml()) for item in model.all())
|
30
|
+
items = "".join(str(item.to_xml().encode('UTF-8')) for item in model.all())
|
31
31
|
if items == "":
|
32
32
|
return '<entities type="array"/>'
|
33
33
|
else:
|
@@ -51,13 +51,13 @@ def update_model_from_params(model, params):
|
|
51
51
|
elif isinstance(getattr(model, k), int) and v != "":
|
52
52
|
setattr(model, k, int(v))
|
53
53
|
elif isinstance(getattr(model, k), datetime.datetime) and v != "":
|
54
|
-
value =
|
54
|
+
value = iso8601.parse_date(v)
|
55
55
|
setattr(model, k, value)
|
56
56
|
elif isinstance(getattr(model, k), datetime.date) and v != "":
|
57
57
|
value = datetime.datetime.strptime(v, "%Y-%m-%d")
|
58
58
|
setattr(model, k, datetime.date(value.year, value.month, value.day))
|
59
59
|
elif isinstance(getattr(model, k), datetime.time) and v != "":
|
60
|
-
value =
|
60
|
+
value = iso8601.parse_date(v)
|
61
61
|
setattr(model, k, datetime.time(value.hour, value.minute, value.second))
|
62
62
|
else:
|
63
63
|
setattr(model, k, v)
|
@@ -0,0 +1,92 @@
|
|
1
|
+
from datetime import datetime, timedelta, tzinfo
|
2
|
+
import re
|
3
|
+
|
4
|
+
__all__ = ["parse_date", "ParseError"]
|
5
|
+
|
6
|
+
# Adapted from http://delete.me.uk/2005/03/iso8601.html
|
7
|
+
ISO8601_REGEX = re.compile(r"(?P<year>[0-9]{4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
|
8
|
+
r"((?P<separator>.)(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2})(:(?P<second>[0-9]{2})(\.(?P<fraction>[0-9]+))?)?"
|
9
|
+
r"(?P<timezone>Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"
|
10
|
+
)
|
11
|
+
TIMEZONE_REGEX = re.compile("(?P<prefix>[+-])(?P<hours>[0-9]{2}).(?P<minutes>[0-9]{2})")
|
12
|
+
|
13
|
+
class ParseError(Exception):
|
14
|
+
"""Raised when there is a problem parsing a date string"""
|
15
|
+
|
16
|
+
# Yoinked from python docs
|
17
|
+
ZERO = timedelta(0)
|
18
|
+
class Utc(tzinfo):
|
19
|
+
"""UTC
|
20
|
+
|
21
|
+
"""
|
22
|
+
def utcoffset(self, dt):
|
23
|
+
return ZERO
|
24
|
+
|
25
|
+
def tzname(self, dt):
|
26
|
+
return "UTC"
|
27
|
+
|
28
|
+
def dst(self, dt):
|
29
|
+
return ZERO
|
30
|
+
UTC = Utc()
|
31
|
+
|
32
|
+
class FixedOffset(tzinfo):
|
33
|
+
"""Fixed offset in hours and minutes from UTC
|
34
|
+
|
35
|
+
"""
|
36
|
+
def __init__(self, offset_hours, offset_minutes, name):
|
37
|
+
self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes)
|
38
|
+
self.__name = name
|
39
|
+
|
40
|
+
def utcoffset(self, dt):
|
41
|
+
return self.__offset
|
42
|
+
|
43
|
+
def tzname(self, dt):
|
44
|
+
return self.__name
|
45
|
+
|
46
|
+
def dst(self, dt):
|
47
|
+
return ZERO
|
48
|
+
|
49
|
+
def __repr__(self):
|
50
|
+
return "<FixedOffset %r>" % self.__name
|
51
|
+
|
52
|
+
def parse_timezone(tzstring, default_timezone=UTC):
|
53
|
+
"""Parses ISO 8601 time zone specs into tzinfo offsets
|
54
|
+
|
55
|
+
"""
|
56
|
+
if tzstring == "Z":
|
57
|
+
return default_timezone
|
58
|
+
# This isn't strictly correct, but it's common to encounter dates without
|
59
|
+
# timezones so I'll assume the default (which defaults to UTC).
|
60
|
+
# Addresses issue 4.
|
61
|
+
if tzstring is None:
|
62
|
+
return default_timezone
|
63
|
+
m = TIMEZONE_REGEX.match(tzstring)
|
64
|
+
prefix, hours, minutes = m.groups()
|
65
|
+
hours, minutes = int(hours), int(minutes)
|
66
|
+
if prefix == "-":
|
67
|
+
hours = -hours
|
68
|
+
minutes = -minutes
|
69
|
+
return FixedOffset(hours, minutes, tzstring)
|
70
|
+
|
71
|
+
def parse_date(datestring, default_timezone=UTC):
|
72
|
+
"""Parses ISO 8601 dates into datetime objects
|
73
|
+
|
74
|
+
The timezone is parsed from the date string. However it is quite common to
|
75
|
+
have dates without a timezone (not strictly correct). In this case the
|
76
|
+
default timezone specified in default_timezone is used. This is UTC by
|
77
|
+
default.
|
78
|
+
"""
|
79
|
+
if not isinstance(datestring, basestring):
|
80
|
+
raise ParseError("Expecting a string %r" % datestring)
|
81
|
+
m = ISO8601_REGEX.match(datestring)
|
82
|
+
if not m:
|
83
|
+
raise ParseError("Unable to parse date string %r" % datestring)
|
84
|
+
groups = m.groupdict()
|
85
|
+
tz = parse_timezone(groups["timezone"], default_timezone=default_timezone)
|
86
|
+
if groups["fraction"] is None:
|
87
|
+
groups["fraction"] = 0
|
88
|
+
else:
|
89
|
+
groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6)
|
90
|
+
return datetime(int(groups["year"]), int(groups["month"]), int(groups["day"]),
|
91
|
+
int(groups["hour"]), int(groups["minute"]), int(groups["second"]),
|
92
|
+
int(groups["fraction"]), tz)
|
@@ -32,8 +32,8 @@ class RxMainAppGenerator < RubiGen::Base
|
|
32
32
|
end
|
33
33
|
|
34
34
|
@component_names = []
|
35
|
-
if File.exists?("#{flex_root}/#{base_folder}/
|
36
|
-
@component_names = list_mxml_files("#{flex_root}/#{base_folder}/
|
35
|
+
if File.exists?("#{flex_root}/#{base_folder}/views/generated")
|
36
|
+
@component_names = list_mxml_files("#{flex_root}/#{base_folder}/views/generated")
|
37
37
|
end
|
38
38
|
|
39
39
|
@controller_names = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
2
2
|
<mx:<%= application_tag %> xmlns:mx="http://www.adobe.com/2006/mxml"
|
3
|
-
xmlns:generated="<%= base_package %>.
|
3
|
+
xmlns:generated="<%= base_package %>.views.generated.*"
|
4
4
|
paddingBottom="8" paddingLeft="8" paddingRight="8" paddingTop="8"
|
5
5
|
layout="horizontal" styleName="plain" initialize="init()">
|
6
6
|
<mx:Script>
|
@@ -14,12 +14,13 @@
|
|
14
14
|
import org.restfulx.events.PushStartEvent;
|
15
15
|
import org.restfulx.controllers.ChangeController;
|
16
16
|
import org.restfulx.services.ISyncingServiceProvider;
|
17
|
-
import org.restfulx.services.http.XMLHTTPServiceProvider;
|
18
17
|
<% end -%>
|
19
18
|
import org.restfulx.services.air.AIRServiceProvider;
|
20
19
|
<% end -%>
|
21
20
|
<% if use_gae -%>
|
22
21
|
import org.restfulx.services.http.GAEHTTPServiceProvider;
|
22
|
+
<% else -%>
|
23
|
+
import org.restfulx.services.http.XMLHTTPServiceProvider;
|
23
24
|
<% end -%>
|
24
25
|
import org.restfulx.Rx;
|
25
26
|
import <%= base_package %>.controllers.<%= command_controller_name %>;
|
@@ -53,9 +54,15 @@
|
|
53
54
|
AIRServiceProvider.ID, "<%= base_package %>");
|
54
55
|
<% if distributed -%>
|
55
56
|
|
57
|
+
<% if use_gae -%>
|
58
|
+
Rx.changes.setSyncProviders(
|
59
|
+
ISyncingServiceProvider(Rx.services.getServiceProvider(AIRServiceProvider.ID)),
|
60
|
+
Rx.services.getServiceProvider(GAEHTTPServiceProvider.ID));
|
61
|
+
<% else -%>
|
56
62
|
Rx.changes.setSyncProviders(
|
57
63
|
ISyncingServiceProvider(Rx.services.getServiceProvider(AIRServiceProvider.ID)),
|
58
64
|
Rx.services.getServiceProvider(XMLHTTPServiceProvider.ID));
|
65
|
+
<% end -%>
|
59
66
|
|
60
67
|
Rx.changes.addEventListener(PushStartEvent.ID, onPushStart);
|
61
68
|
Rx.changes.addEventListener(PushEndEvent.ID, onPushEnd);
|
@@ -93,7 +100,11 @@
|
|
93
100
|
online = (socketMonitor.available) ? true : false;
|
94
101
|
|
95
102
|
if (online) {
|
103
|
+
<% if use_gae -%>
|
104
|
+
Rx.defaultServiceId = GAEHTTPServiceProvider.ID;
|
105
|
+
<% else -%>
|
96
106
|
Rx.defaultServiceId = XMLHTTPServiceProvider.ID;
|
107
|
+
<% end -%>
|
97
108
|
} else {
|
98
109
|
Rx.defaultServiceId = AIRServiceProvider.ID;
|
99
110
|
}
|
@@ -101,8 +112,13 @@
|
|
101
112
|
|
102
113
|
private function getCurrentProviderName(id:int):String {
|
103
114
|
switch (id) {
|
115
|
+
<% if use_gae -%>
|
116
|
+
case GAEHTTPServiceProvider.ID:
|
117
|
+
return "GAE";
|
118
|
+
<% else -%>
|
104
119
|
case XMLHTTPServiceProvider.ID:
|
105
|
-
return "
|
120
|
+
return "XML/HTTP";
|
121
|
+
<% end -%>
|
106
122
|
case AIRServiceProvider.ID:
|
107
123
|
return "AIR (SQLite)";
|
108
124
|
default :
|
@@ -70,7 +70,14 @@ class RxScaffoldGenerator < RubiGen::Base
|
|
70
70
|
|
71
71
|
attr_reader :belongs_tos,
|
72
72
|
:has_manies,
|
73
|
-
:has_ones
|
73
|
+
:has_ones,
|
74
|
+
:attachment_field,
|
75
|
+
:has_many_through,
|
76
|
+
:polymorphic,
|
77
|
+
:tree_model,
|
78
|
+
:layout,
|
79
|
+
:ignored_fields,
|
80
|
+
:args_for_generation
|
74
81
|
|
75
82
|
attr_reader :name,
|
76
83
|
:class_name,
|
@@ -93,14 +100,20 @@ class RxScaffoldGenerator < RubiGen::Base
|
|
93
100
|
end
|
94
101
|
|
95
102
|
def manifest
|
96
|
-
record do |m|
|
103
|
+
record do |m|
|
97
104
|
m.template 'model.as.erb',
|
98
105
|
File.join("#{flex_root}", base_folder, "models", "#{@class_name}.as"),
|
99
106
|
:assigns => { :resource_controller_name => "#{file_name.pluralize}" }
|
100
107
|
|
101
|
-
|
102
|
-
|
103
|
-
|
108
|
+
if @layout.size > 0
|
109
|
+
m.template "layouts/#{@layout}.erb",
|
110
|
+
File.join("#{@flex_root}", base_folder, "views", "generated", "#{@class_name}Box.mxml"),
|
111
|
+
:assigns => { :resource_controller_name => "#{file_name.pluralize}" }
|
112
|
+
else
|
113
|
+
m.template "layouts/#{RxSettings.layouts.default}.erb",
|
114
|
+
File.join("#{@flex_root}", base_folder, "views", "generated", "#{@class_name}Box.mxml"),
|
115
|
+
:assigns => { :resource_controller_name => "#{file_name.pluralize}" }
|
116
|
+
end
|
104
117
|
|
105
118
|
if options[:gae]
|
106
119
|
m.template 'controller.py.erb', "app/controllers/#{file_name.pluralize}.py"
|
@@ -113,23 +126,57 @@ class RxScaffoldGenerator < RubiGen::Base
|
|
113
126
|
|
114
127
|
protected
|
115
128
|
def extract_relationships
|
129
|
+
# arrays
|
116
130
|
@belongs_tos = []
|
117
131
|
@has_ones = []
|
118
132
|
@has_manies = []
|
119
|
-
|
133
|
+
@attachment_field = []
|
134
|
+
@polymorphic = []
|
135
|
+
@tree_model = []
|
136
|
+
@layout = []
|
137
|
+
@ignored_fields = []
|
138
|
+
|
139
|
+
# hashes
|
140
|
+
@has_many_through = {}
|
141
|
+
|
120
142
|
@args.each do |arg|
|
143
|
+
# arrays
|
121
144
|
if arg =~ /^has_one:/
|
122
|
-
# arg = "has_one:arg1,arg2", so all the has_one are together
|
123
145
|
@has_ones = arg.split(':')[1].split(',')
|
124
146
|
elsif arg =~ /^has_many:/
|
125
|
-
# arg = "has_many:arg1,arg2", so all the has_many are together
|
126
147
|
@has_manies = arg.split(":")[1].split(",")
|
127
|
-
elsif arg =~ /^belongs_to:/
|
148
|
+
elsif arg =~ /^belongs_to:/
|
128
149
|
@belongs_tos = arg.split(":")[1].split(',')
|
150
|
+
elsif arg =~ /^attachment_field:/
|
151
|
+
@attachment_field = arg.split(":")[1].split(',')
|
152
|
+
elsif arg =~ /^polymorphic:/
|
153
|
+
@polymorphic = arg.split(":")[1].split(',')
|
154
|
+
elsif arg =~ /^tree_model:/
|
155
|
+
@tree_model = arg.split(":")[1].split(',')
|
156
|
+
elsif arg =~ /^layout:/
|
157
|
+
@layout = arg.split(":")[1].split(',')
|
158
|
+
elsif arg =~ /^ignored_fields:/
|
159
|
+
@ignored_fields = arg.split(":")[1].split(',')
|
160
|
+
# hashes
|
161
|
+
elsif arg =~ /^has_many_through:/
|
162
|
+
hmt_arr = arg.split(":")[1].split(',')
|
163
|
+
@has_many_through[hmt_arr.first] = hmt_arr.last
|
129
164
|
end
|
130
165
|
end
|
131
166
|
|
132
|
-
|
167
|
+
# delete special fields from @args ivar
|
168
|
+
%w(has_one has_many belongs_to attachment_field has_many_through
|
169
|
+
polymorphic tree_model layout ignored_fields).each do |special_field|
|
170
|
+
@args.delete_if { |f| f =~ /^(#{special_field}):/ }
|
171
|
+
end
|
172
|
+
|
173
|
+
@args_for_generation = @args.clone
|
174
|
+
|
175
|
+
# delete ignored_fields from @args ivar
|
176
|
+
@ignored_fields.each do |ignored|
|
177
|
+
@args.delete_if { |f| f =~ /^(#{ignored}):/ }
|
178
|
+
end
|
179
|
+
|
133
180
|
end
|
134
181
|
|
135
182
|
def attributes
|