dima-restfulx 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/Manifest.txt +127 -0
- data/README.rdoc +50 -0
- data/Rakefile +42 -0
- data/app_generators/rx_app/USAGE +22 -0
- data/app_generators/rx_app/rx_app_generator.rb +94 -0
- data/app_generators/rx_app/templates/actionscript.properties +16 -0
- data/app_generators/rx_app/templates/actionscriptair.properties +16 -0
- data/app_generators/rx_app/templates/app.yaml.erb +12 -0
- data/app_generators/rx_app/templates/default_tasks.rake +51 -0
- data/app_generators/rx_app/templates/empty.txt +0 -0
- data/app_generators/rx_app/templates/expressInstall.swf +0 -0
- data/app_generators/rx_app/templates/flex.properties +2 -0
- data/app_generators/rx_app/templates/generate.rb +17 -0
- data/app_generators/rx_app/templates/html-template/AC_OETags.js +276 -0
- data/app_generators/rx_app/templates/html-template/history/history.css +6 -0
- data/app_generators/rx_app/templates/html-template/history/history.js +645 -0
- data/app_generators/rx_app/templates/html-template/history/historyFrame.html +29 -0
- data/app_generators/rx_app/templates/html-template/index.template.html +121 -0
- data/app_generators/rx_app/templates/html-template/playerProductInstall.swf +0 -0
- data/app_generators/rx_app/templates/index.html.erb +18 -0
- data/app_generators/rx_app/templates/index.yaml +11 -0
- data/app_generators/rx_app/templates/mainair-app.xml +134 -0
- data/app_generators/rx_app/templates/mainapp-config.xml +21 -0
- data/app_generators/rx_app/templates/mainapp.mxml +31 -0
- data/app_generators/rx_app/templates/project-textmate.erb +52 -0
- data/app_generators/rx_app/templates/project.properties +18 -0
- data/app_generators/rx_app/templates/projectair.properties +24 -0
- data/app_generators/rx_app/templates/swfobject.js +5 -0
- data/bin/rx-gen +31 -0
- data/generators/rx_config/USAGE +5 -0
- data/generators/rx_config/rx_config_generator.rb +19 -0
- data/generators/rx_controller/USAGE +10 -0
- data/generators/rx_controller/rx_controller_generator.rb +39 -0
- data/generators/rx_controller/templates/assist.py +65 -0
- data/generators/rx_controller/templates/controller.as.erb +36 -0
- data/generators/rx_controller/templates/restful.py +136 -0
- data/generators/rx_main_app/USAGE +8 -0
- data/generators/rx_main_app/rx_main_app_generator.rb +60 -0
- data/generators/rx_main_app/templates/main.py.erb +29 -0
- data/generators/rx_main_app/templates/mainapp.mxml +35 -0
- data/generators/rx_scaffold/USAGE +29 -0
- data/generators/rx_scaffold/rx_scaffold_generator.rb +146 -0
- data/generators/rx_scaffold/templates/component.mxml.erb +149 -0
- data/generators/rx_scaffold/templates/controller.py.erb +27 -0
- data/generators/rx_scaffold/templates/model.as.erb +42 -0
- data/generators/rx_scaffold/templates/model.py.erb +14 -0
- data/generators/rx_yaml_scaffold/USAGE +45 -0
- data/generators/rx_yaml_scaffold/rx_yaml_scaffold_generator.rb +47 -0
- data/lib/restfulx/active_foo.rb +186 -0
- data/lib/restfulx/active_record_tasks.rb +81 -0
- data/lib/restfulx/configuration.rb +76 -0
- data/lib/restfulx/datamapper_foo.rb +31 -0
- data/lib/restfulx/rails/recipes.rb +60 -0
- data/lib/restfulx/rails/swf_helper.rb +60 -0
- data/lib/restfulx/tasks.rb +85 -0
- data/lib/restfulx.rb +117 -0
- data/rails_generators/rx_config/USAGE +18 -0
- data/rails_generators/rx_config/rx_config_generator.rb +115 -0
- data/rails_generators/rx_config/templates/actionscript.properties +16 -0
- data/rails_generators/rx_config/templates/actionscriptair.properties +16 -0
- data/rails_generators/rx_config/templates/expressInstall.swf +0 -0
- data/rails_generators/rx_config/templates/flex.properties +2 -0
- data/rails_generators/rx_config/templates/html-template/AC_OETags.js +276 -0
- data/rails_generators/rx_config/templates/html-template/history/history.css +6 -0
- data/rails_generators/rx_config/templates/html-template/history/history.js +645 -0
- data/rails_generators/rx_config/templates/html-template/history/historyFrame.html +29 -0
- data/rails_generators/rx_config/templates/html-template/index.template.html +121 -0
- data/rails_generators/rx_config/templates/html-template/playerProductInstall.swf +0 -0
- data/rails_generators/rx_config/templates/index.html.erb +18 -0
- data/rails_generators/rx_config/templates/mainair-app.xml +134 -0
- data/rails_generators/rx_config/templates/mainapp-config.xml +21 -0
- data/rails_generators/rx_config/templates/mainapp.mxml +31 -0
- data/rails_generators/rx_config/templates/project-textmate.erb +52 -0
- data/rails_generators/rx_config/templates/project.properties +18 -0
- data/rails_generators/rx_config/templates/projectair.properties +24 -0
- data/rails_generators/rx_config/templates/restfulx.yml +14 -0
- data/rails_generators/rx_config/templates/restfulx_tasks.rake +6 -0
- data/rails_generators/rx_config/templates/swfobject.js +5 -0
- data/rails_generators/rx_controller/USAGE +10 -0
- data/rails_generators/rx_controller/rx_controller_generator.rb +28 -0
- data/rails_generators/rx_controller/templates/controller.as.erb +40 -0
- data/rails_generators/rx_scaffold/USAGE +35 -0
- data/rails_generators/rx_scaffold/rx_scaffold_generator.rb +179 -0
- data/rails_generators/rx_scaffold/templates/component.mxml.erb +149 -0
- data/rails_generators/rx_scaffold/templates/controller.rb.erb +97 -0
- data/rails_generators/rx_scaffold/templates/fixtures.yml.erb +35 -0
- data/rails_generators/rx_scaffold/templates/migration.rb.erb +19 -0
- data/rails_generators/rx_scaffold/templates/model.as.erb +42 -0
- data/rails_generators/rx_scaffold/templates/model.rb.erb +11 -0
- data/rails_generators/rx_yaml_scaffold/USAGE +51 -0
- data/rails_generators/rx_yaml_scaffold/rx_yaml_scaffold_generator.rb +49 -0
- data/rdoc/generators/template/html/jamis.rb +588 -0
- data/spec/restfulx_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/test/rails/controllers/application.rb +15 -0
- data/test/rails/controllers/locations_controller.rb +93 -0
- data/test/rails/controllers/notes_controller.rb +96 -0
- data/test/rails/controllers/projects_controller.rb +93 -0
- data/test/rails/controllers/tasks_controller.rb +93 -0
- data/test/rails/controllers/users_controller.rb +93 -0
- data/test/rails/database.yml +4 -0
- data/test/rails/fixtures/locations.yml +8 -0
- data/test/rails/fixtures/notes.yml +17 -0
- data/test/rails/fixtures/projects.yml +25 -0
- data/test/rails/fixtures/simple_properties.yml +19 -0
- data/test/rails/fixtures/tasks.yml +46 -0
- data/test/rails/fixtures/users.yml +13 -0
- data/test/rails/helpers/functional_test_helper.rb +21 -0
- data/test/rails/helpers/test_helper.rb +61 -0
- data/test/rails/helpers/unit_test_helper.rb +30 -0
- data/test/rails/model.yml +35 -0
- data/test/rails/models/location.rb +4 -0
- data/test/rails/models/note.rb +3 -0
- data/test/rails/models/project.rb +4 -0
- data/test/rails/models/simple_property.rb +2 -0
- data/test/rails/models/task.rb +18 -0
- data/test/rails/models/user.rb +20 -0
- data/test/rails/playing_around_in_a_console.txt +71 -0
- data/test/rails/schema.rb +77 -0
- data/test/rails/test.swf +1 -0
- data/test/rails/test_active_foo.rb +36 -0
- data/test/rails/test_rails_integration_functional.rb +22 -0
- data/test/rails/test_to_fxml.rb +35 -0
- data/test/rails/test_to_json.rb +23 -0
- data/test/rails/views/notes/empty_params_action.html.erb +1 -0
- data/test/rails/views/notes/index.html.erb +1 -0
- metadata +211 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
package <%= base_package %>.models {
|
2
|
+
<% if has_manies.length > 0 -%>
|
3
|
+
import org.restfulx.collections.ModelsCollection;
|
4
|
+
<% end -%>
|
5
|
+
import org.restfulx.models.RxModel;
|
6
|
+
|
7
|
+
[Resource(name="<%= resource_controller_name %>")]
|
8
|
+
[Bindable]
|
9
|
+
public class <%= class_name %> extends RxModel {
|
10
|
+
<% if attributes && !attributes.empty? && attributes[0].flex_type != "Boolean" -%>
|
11
|
+
public static const LABEL:String = "<%= attributes[0].flex_name %>";
|
12
|
+
<% else -%>
|
13
|
+
public static const LABEL:String = "id";
|
14
|
+
<% end -%>
|
15
|
+
|
16
|
+
<% for attribute in attributes -%>
|
17
|
+
<% if attribute.type == :datetime || attribute.type == :time -%>
|
18
|
+
[DateTime]
|
19
|
+
<% end -%>
|
20
|
+
public var <%= attribute.flex_name %>:<%= attribute.flex_type %> = <%= attribute.flex_default %>;
|
21
|
+
|
22
|
+
<% end -%>
|
23
|
+
<% for model in belongs_tos -%>
|
24
|
+
[BelongsTo]
|
25
|
+
public var <%= model.camelcase(:lower) %>:<%= model.camelcase %>;
|
26
|
+
|
27
|
+
<% end -%>
|
28
|
+
<% for model in has_ones -%>
|
29
|
+
[HasOne]
|
30
|
+
public var <%= model.camelcase(:lower) %>:<%= model.camelcase %>;
|
31
|
+
|
32
|
+
<% end -%>
|
33
|
+
<% for model in has_manies -%>
|
34
|
+
[HasMany]
|
35
|
+
public var <%= model.camelcase(:lower) %>:ModelsCollection;
|
36
|
+
|
37
|
+
<% end -%>
|
38
|
+
public function <%= class_name %>() {
|
39
|
+
super(LABEL);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
@@ -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
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
Description:
|
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 "rx_scaffold".
|
6
|
+
|
7
|
+
Examples:
|
8
|
+
`./script/generate rx_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]
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class RxYamlScaffoldGenerator < RubiGen::Base
|
4
|
+
include RestfulX::Configuration
|
5
|
+
|
6
|
+
def extract_attrs(line, attrs)
|
7
|
+
attrs.each do |key,value|
|
8
|
+
if value.class == Array
|
9
|
+
line << " #{key}:#{value.join(',')}"
|
10
|
+
else
|
11
|
+
line << " #{key}:#{value}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
line
|
15
|
+
end
|
16
|
+
|
17
|
+
def manifest
|
18
|
+
record do |m|
|
19
|
+
models = YAML.load(File.open(File.join(APP_ROOT, 'db/model.yml'), 'r'))
|
20
|
+
models.each do |model|
|
21
|
+
line = ""
|
22
|
+
attrs = model[1]
|
23
|
+
if attrs.class == Array
|
24
|
+
attrs.each do |elm|
|
25
|
+
line = extract_attrs(line, elm)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
line = extract_attrs(line, attrs)
|
29
|
+
end
|
30
|
+
line = model[0].camelcase + " " + line
|
31
|
+
puts 'running: rx_scaffold ' + line
|
32
|
+
RubiGen::Scripts::Generate.new.run(line.split, :generator => 'rx_scaffold',
|
33
|
+
:gae => options[:gae])
|
34
|
+
puts 'done ...'
|
35
|
+
end
|
36
|
+
RubiGen::Scripts::Generate.new.run([], :generator => 'rx_main_app', :gae => options[:gae])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
def add_options!(opt)
|
42
|
+
opt.separator ''
|
43
|
+
opt.separator 'Options:'
|
44
|
+
opt.on("--gae", "Generate Google App Engine Python classes in addition to RestfulX Flex resources.",
|
45
|
+
"Default: false") { |v| options[:gae] = v }
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# There's a number of things that ActiveRecord/ActiveSupport and the rest of the family get
|
2
|
+
# ~wrong~ from the point of view of Flex clients.
|
3
|
+
#
|
4
|
+
# Some of these things are:
|
5
|
+
# * Date formats
|
6
|
+
# * XML format (Flex *really* doesn't like dashes in XML messages)
|
7
|
+
# * Errors (we need to be more specific and communicate what went wrong *where*)
|
8
|
+
#
|
9
|
+
# This is where we try to fix this stuff.
|
10
|
+
#
|
11
|
+
# Some of the things that are done can be called _monkey_ _patching_ while others can
|
12
|
+
# be called extensions. Caveat emptor.
|
13
|
+
|
14
|
+
# Flex friendly date, datetime formats
|
15
|
+
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(:flex_date => "%Y/%m/%d")
|
16
|
+
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:flex_datetime => "%Y/%m/%d %H:%M:%S")
|
17
|
+
|
18
|
+
Hash::XML_FORMATTING['date'] = Proc.new { |date| date.to_s(:flex_date) }
|
19
|
+
Hash::XML_FORMATTING['datetime'] = Proc.new { |datetime| datetime.to_s(:flex_datetime) }
|
20
|
+
|
21
|
+
# ActiveSupport specific patches. More specifically we add +to_fxml+ methods to Array and
|
22
|
+
# Hash conversion modules
|
23
|
+
module ActiveSupport
|
24
|
+
# refer to: http://api.rubyonrails.org/ for more details
|
25
|
+
module CoreExtensions
|
26
|
+
# Add Flex friendly +to_fxml+ to Hash conversions
|
27
|
+
module Hash
|
28
|
+
# refer to: http://api.rubyonrails.org/ for more details
|
29
|
+
module Conversions
|
30
|
+
|
31
|
+
# Flex friendly XML format, no dashes, etc
|
32
|
+
def to_fxml(options = {})
|
33
|
+
options.merge!(:dasherize => false)
|
34
|
+
options[:indent] ||= 2
|
35
|
+
options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]),
|
36
|
+
:root => "hash" })
|
37
|
+
options[:builder].instruct! unless options.delete(:skip_instruct)
|
38
|
+
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
|
39
|
+
root = dasherize ? options[:root].to_s.dasherize : options[:root].to_s
|
40
|
+
|
41
|
+
options[:builder].__send__(:method_missing, root) do
|
42
|
+
each do |key, value|
|
43
|
+
case value
|
44
|
+
when ::Hash
|
45
|
+
value.to_fxml(options.merge({ :root => key, :skip_instruct => true }))
|
46
|
+
when ::Array
|
47
|
+
value.to_fxml(options.merge({ :root => key, :children => key.to_s.singularize, :skip_instruct => true}))
|
48
|
+
when ::Method, ::Proc
|
49
|
+
# If the Method or Proc takes two arguments, then
|
50
|
+
# pass the suggested child element name. This is
|
51
|
+
# used if the Method or Proc will be operating over
|
52
|
+
# multiple records and needs to create an containing
|
53
|
+
# element that will contain the objects being
|
54
|
+
# serialized.
|
55
|
+
if 1 == value.arity
|
56
|
+
value.call(options.merge({ :root => key, :skip_instruct => true }))
|
57
|
+
else
|
58
|
+
value.call(options.merge({ :root => key, :skip_instruct => true }), key.to_s.singularize)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
if value.respond_to?(:to_fxml)
|
62
|
+
value.to_fxml(options.merge({ :root => key, :skip_instruct => true }))
|
63
|
+
else
|
64
|
+
type_name = XML_TYPE_NAMES[value.class.name]
|
65
|
+
|
66
|
+
key = dasherize ? key.to_s.dasherize : key.to_s
|
67
|
+
|
68
|
+
attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name }
|
69
|
+
if value.nil?
|
70
|
+
attributes[:nil] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
options[:builder].tag!(key,
|
74
|
+
XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value,
|
75
|
+
attributes
|
76
|
+
)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
yield options[:builder] if block_given?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
# Add Flex friendly to_fxml to array conversions
|
87
|
+
module Array
|
88
|
+
# refer to: http://api.rubyonrails.org/ for more details
|
89
|
+
module Conversions
|
90
|
+
# Flex friendly XML format (no dashes, etc)
|
91
|
+
def to_fxml(options = {})
|
92
|
+
raise "Not all elements respond to to_fxml" unless all? { |e| e.respond_to? :to_fxml }
|
93
|
+
|
94
|
+
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records"
|
95
|
+
options[:children] ||= options[:root].singularize
|
96
|
+
options[:indent] ||= 2
|
97
|
+
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
98
|
+
options.merge!(:dasherize => false)
|
99
|
+
|
100
|
+
root = options.delete(:root).to_s
|
101
|
+
children = options.delete(:children)
|
102
|
+
|
103
|
+
if !options.has_key?(:dasherize) || options[:dasherize]
|
104
|
+
root = root.dasherize
|
105
|
+
end
|
106
|
+
|
107
|
+
options[:builder].instruct! unless options.delete(:skip_instruct)
|
108
|
+
|
109
|
+
opts = options.merge({ :root => children })
|
110
|
+
|
111
|
+
xml = options[:builder]
|
112
|
+
if empty?
|
113
|
+
xml.tag!(root, options[:skip_types] ? {} : {:type => "array"})
|
114
|
+
else
|
115
|
+
xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) {
|
116
|
+
yield xml if block_given?
|
117
|
+
each { |e| e.to_fxml(opts.merge!({ :skip_instruct => true })) }
|
118
|
+
}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Flex friendly ActiveRecord patches. More specifically XML serialization improvements.
|
127
|
+
# These won't override whatever you may normally do with XML, hence there's Flex specific
|
128
|
+
# name for this stuff +to_fxml+.
|
129
|
+
module ActiveRecord
|
130
|
+
# refer to: http://api.rubyonrails.org/ for more details
|
131
|
+
module Serialization
|
132
|
+
# Enforces Flex friendly options on XML and delegates processing to standard +to_xml+
|
133
|
+
def to_fxml(options = {}, &block)
|
134
|
+
options.merge!(:dasherize => false)
|
135
|
+
default_except = [:crypted_password, :salt, :remember_token, :remember_token_expires_at]
|
136
|
+
options[:except] = (options[:except] ? options[:except] + default_except : default_except)
|
137
|
+
to_xml(options, &block)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Change the xml serializer so that '?'s are stripped from attribute names.
|
142
|
+
# This makes it possible to serialize methods that end in a question mark, like 'valid?' or 'is_true?'
|
143
|
+
class XmlSerializer
|
144
|
+
# Strips '?' from serialized method names
|
145
|
+
def add_tag(attribute)
|
146
|
+
builder.tag!(
|
147
|
+
dasherize? ? attribute.display_name.dasherize : attribute.display_name,
|
148
|
+
attribute.value.to_s,
|
149
|
+
attribute.decorations(!options[:skip_types])
|
150
|
+
)
|
151
|
+
end
|
152
|
+
# Strips '?' from serialized method names
|
153
|
+
class Attribute
|
154
|
+
# Strips '?' from serialized method names
|
155
|
+
def display_name
|
156
|
+
@name.gsub('?','')
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Add more extensive reporting on errors including field name along with a message
|
162
|
+
# when errors are serialized to XML
|
163
|
+
class Errors
|
164
|
+
# Flex friendly errors
|
165
|
+
def to_fxml(options={})
|
166
|
+
options[:root] ||= "errors"
|
167
|
+
options[:indent] ||= 2
|
168
|
+
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
169
|
+
options[:builder].instruct! unless options.delete(:skip_instruct)
|
170
|
+
options[:builder].errors do |e|
|
171
|
+
# The @errors instance variable is a Hash inside the Errors class
|
172
|
+
@errors.each_key do |attr|
|
173
|
+
@errors[attr].each do |msg|
|
174
|
+
next if msg.nil?
|
175
|
+
if attr == "base"
|
176
|
+
options[:builder].error("message" => msg)
|
177
|
+
else
|
178
|
+
fullmsg = @base.class.human_attribute_name(attr) + ' ' + msg
|
179
|
+
options[:builder].error("field" => attr.camelcase(:lower), "message" => fullmsg)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# ActiveRecord specific Rake tasks. Namely, nice little extras such as:
|
2
|
+
# - db:mysql:stage
|
3
|
+
# - db:refresh
|
4
|
+
require File.join(File.dirname(__FILE__), 'tasks')
|
5
|
+
|
6
|
+
# stores local copy of the application environment ('production', 'test', etc)
|
7
|
+
# so that appropriate values in config/database.yml are used
|
8
|
+
APP_ENV = defined?(ENV['RAILS_ENV']) ? ENV['RAILS_ENV'] : ENV['MERB_ENV']
|
9
|
+
|
10
|
+
namespace :db do
|
11
|
+
namespace :mysql do
|
12
|
+
namespace :stage do
|
13
|
+
desc "Stage production, test and development databases"
|
14
|
+
task :all do
|
15
|
+
db_names = %w(development test production)
|
16
|
+
admin_password = ENV["ADMINPASS"] || ""
|
17
|
+
db_user_name = ENV["USER"] || "root"
|
18
|
+
db_password = ENV["PASS"] || ""
|
19
|
+
stage_database(db_names, admin_password, db_user_name, db_password)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Stage the database environment for #{APP_ENV}"
|
24
|
+
task :stage do
|
25
|
+
db_names = [APP_ENV]
|
26
|
+
admin_password = ENV["ADMINPASS"] || ""
|
27
|
+
db_user_name = ENV["USER"] || "root"
|
28
|
+
db_password = ENV["PASS"] || ""
|
29
|
+
stage_database(db_names, admin_password, db_user_name, db_password)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Performs MySQL database set-up based on the username and password
|
34
|
+
# provided. Also updates Rails config/database.yml file with database
|
35
|
+
# username and password
|
36
|
+
def stage_database(db_names, admin_password, db_user_name, db_password)
|
37
|
+
sql_command = ""
|
38
|
+
|
39
|
+
db_names.each do |name|
|
40
|
+
db_name = ActiveRecord::Base.configurations[name]['database']
|
41
|
+
sql_command += "drop database if exists #{db_name}; " <<
|
42
|
+
"create database #{db_name}; grant all privileges on #{db_name}.* " <<
|
43
|
+
"to #{db_user_name}@localhost identified by \'#{db_password}\';"
|
44
|
+
ActiveRecord::Base.configurations[name]['username'] = db_user_name
|
45
|
+
ActiveRecord::Base.configurations[name]['password'] = db_password
|
46
|
+
end
|
47
|
+
|
48
|
+
if (!File.exist?("#{APP_ROOT}/tmp/stage.sql"))
|
49
|
+
File.open("#{APP_ROOT}/tmp/stage.sql", "w") do |file|
|
50
|
+
file.print sql_command
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# back up the original database.yml file just in case
|
55
|
+
File.copy("#{APP_ROOT}/config/database.yml",
|
56
|
+
"#{APP_ROOT}/config/database.yml.sample") if !File.exist?("#{APP_ROOT}/config/database.yml.sample")
|
57
|
+
|
58
|
+
dbconfig = File.read("#{APP_ROOT}/config/database.yml")
|
59
|
+
dbconfig.gsub!(/username:.*/, "username: #{db_user_name}")
|
60
|
+
dbconfig.gsub!(/password:.*/, "password: #{db_password}")
|
61
|
+
|
62
|
+
File.open("#{APP_ROOT}/config/database.yml", "w") do |file|
|
63
|
+
file.print dbconfig
|
64
|
+
end
|
65
|
+
|
66
|
+
if system %(mysql -h localhost -u root --password=#{admin_password} < tmp/stage.sql)
|
67
|
+
puts "Updated config/database.yml and staged the database based on your settings"
|
68
|
+
File.delete("tmp/stage.sql") if File.file?("tmp/stage.sql")
|
69
|
+
else
|
70
|
+
puts "Staging was not performed. Check console for errors. It is possible that 'mysql' executable was not found."
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "Drop the database environment for #{APP_ENV} only if it exists"
|
75
|
+
task :drop_if_exists do
|
76
|
+
Rake::Task["db:drop"].invoke rescue nil
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Refresh the database environment for #{APP_ENV}"
|
80
|
+
task :refresh => ['db:drop_if_exists', 'db:create', 'db:migrate', 'db:fixtures:load']
|
81
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Interestingly enough there's no way to *just* upper-case or down-case first letter of a given
|
2
|
+
# string. Ruby's own +capitalize+ actually downcases all the rest of the characters in the string
|
3
|
+
# We patch the class to add our own implementation.
|
4
|
+
class String
|
5
|
+
# Upper-case first character of a string leave the rest of the string intact
|
6
|
+
def ucfirst
|
7
|
+
self[0,1].capitalize + self[1..-1]
|
8
|
+
end
|
9
|
+
|
10
|
+
# Down-case first character of a string leaving the rest of it intact
|
11
|
+
def dcfirst
|
12
|
+
self[0,1].downcase + self[1..-1]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module RestfulX
|
17
|
+
# Computes necessary configuration options from the environment. This can be used in Rails, Merb
|
18
|
+
# or standalone from the command line.
|
19
|
+
module Configuration
|
20
|
+
APP_ROOT = defined?(RAILS_ROOT) ? RAILS_ROOT : defined?(Merb) ? Merb.root : File.expand_path(".")
|
21
|
+
|
22
|
+
# Extract project, package, controller names from the environment. This will respect
|
23
|
+
# config/restfulx.yml if it exists, you can override all of the defaults there. The defaults are:
|
24
|
+
# - *base-package* same as project name downcased
|
25
|
+
# - *controller-name* 'ApplicationController'
|
26
|
+
#
|
27
|
+
# Here's a sample restfulx.yml file:
|
28
|
+
#
|
29
|
+
# RestfulX code generation configuration options
|
30
|
+
#
|
31
|
+
# By default flex models, commands, controllers and components are genearated into
|
32
|
+
# app/flex/<your rails project name> folder. If you'd like to customize the target folder
|
33
|
+
# (to say append a "com" package before your rails project name) uncomment the line below
|
34
|
+
# base-package must follow the usual flex package notation (a string separated by ".")
|
35
|
+
#
|
36
|
+
# base-package: com.pomodo
|
37
|
+
#
|
38
|
+
# Main RestfulX controller is typically named AppicationController. This controller is created in
|
39
|
+
# <base-package>.controllers folder. You can customize the name by uncommenting the following line
|
40
|
+
# and changing the controller name.
|
41
|
+
#
|
42
|
+
# controller-name: ApplicationController
|
43
|
+
def extract_names(project = nil)
|
44
|
+
if project
|
45
|
+
project_name = project.camelcase.gsub(/\s/, '')
|
46
|
+
project_name_downcase = project_name.downcase
|
47
|
+
else
|
48
|
+
project_name = APP_ROOT.split("/").last.camelcase.gsub(/\s/, '')
|
49
|
+
project_name_downcase = project_name.downcase
|
50
|
+
end
|
51
|
+
|
52
|
+
# give a chance to override the settings via restfulx.yml
|
53
|
+
begin
|
54
|
+
config = YAML.load(File.open("#{APP_ROOT}/config/restfulx.yml"))
|
55
|
+
base_package = config['base-package'] || project_name_downcase
|
56
|
+
base_folder = base_package.gsub('.', '/').gsub(/\s/, '')
|
57
|
+
project_name = config['project-name'].camelcase.gsub(/\s/, '') || project_name
|
58
|
+
controller_name = config['controller-name'] || "ApplicationController"
|
59
|
+
rescue
|
60
|
+
base_folder = base_package = project_name_downcase
|
61
|
+
controller_name = "ApplicationController"
|
62
|
+
end
|
63
|
+
[project_name, project_name_downcase, controller_name, base_package, base_folder]
|
64
|
+
end
|
65
|
+
|
66
|
+
# List files ending in *.as (ActionScript) in a given folder
|
67
|
+
def list_as_files(dir_name)
|
68
|
+
Dir.entries(dir_name).grep(/\.as$/).map { |name| name.sub(/\.as$/, "") }.join(", ")
|
69
|
+
end
|
70
|
+
|
71
|
+
# List files ending in *.mxml in a given folder
|
72
|
+
def list_mxml_files(dir_name)
|
73
|
+
Dir.entries(dir_name).grep(/\.mxml$/).map { |name| name.sub(/\.mxml$/, "") }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require RestfulX::LIB_DIR + 'configuration'
|
3
|
+
|
4
|
+
# Flex friendly DataMapper patches, more specifically we just add +to_xml+ on
|
5
|
+
# ValidationErrors class
|
6
|
+
module DataMapper
|
7
|
+
# see DataMapper docs for more details
|
8
|
+
module Validate
|
9
|
+
# By default DataMapper validation errors doesn't have +to_xml+ method. This is
|
10
|
+
# actually very useful when dealing with remote stateful clients such as Flex/AIR.
|
11
|
+
class ValidationErrors
|
12
|
+
# Add Flex-friendly +to_xml+ implementation
|
13
|
+
def to_xml
|
14
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
15
|
+
xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
|
16
|
+
xml.errors do |e|
|
17
|
+
@errors.each_key do |attribute|
|
18
|
+
@errors[attribute].each do |msg|
|
19
|
+
next if msg.nil?
|
20
|
+
if attribute == "base"
|
21
|
+
e.error("message" => msg)
|
22
|
+
else
|
23
|
+
e.error("field" => attribute.to_s.camelcase(:lower), "message" => msg)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Adds Capistrano recipes for deploying Flex applications
|
2
|
+
#
|
3
|
+
# To use these recipes, add the following to your Capfile:
|
4
|
+
#
|
5
|
+
# require 'restfulx/rails/recipes'
|
6
|
+
require 'find'
|
7
|
+
|
8
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
9
|
+
after "deploy:setup", "deploy:flex:setup"
|
10
|
+
|
11
|
+
namespace :db do
|
12
|
+
desc "runs db:refresh in the latest release directory."
|
13
|
+
task :refresh, :roles => :db do
|
14
|
+
run("cd #{latest_release} && rake db:refresh RAILS_ENV=production")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :deploy do
|
19
|
+
namespace :flex do
|
20
|
+
|
21
|
+
desc "Creates the flex_files directory in the shared directory"
|
22
|
+
task :setup do
|
23
|
+
flex_dir = File.join(shared_path, 'flex_files')
|
24
|
+
run "#{try_sudo} mkdir -p #{flex_dir} && #{try_sudo} chmod g+w #{flex_dir}"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "uploads everything in public/bin up to the server"
|
28
|
+
task :via_dumb_copy, :roles => :app do
|
29
|
+
# the -p flag on mkdir makes intermediate directories (i.e. both /bin and /bin/history),
|
30
|
+
# and doesn't raise an error if any of the directories already exist.
|
31
|
+
rails_root = Dir.pwd # You have to run cap tasks from RAILS_ROOT anyways
|
32
|
+
base_dir = File.join(rails_root, 'public', 'bin')
|
33
|
+
ec2_base_dir = File.join(shared_path, 'flex_files')
|
34
|
+
|
35
|
+
Find.find(base_dir) do |file|
|
36
|
+
filename_without_base_dir = file.sub(base_dir, '')
|
37
|
+
if File.directory?(file)
|
38
|
+
run "mkdir -p #{File.join(ec2_base_dir, filename_without_base_dir)}"
|
39
|
+
else
|
40
|
+
content = File.open(file, 'rb') {|f| f.read}
|
41
|
+
put content, File.join(ec2_base_dir, filename_without_base_dir)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "synchronizes the local and remote public/bin directories using rsync"
|
47
|
+
task :via_rsync, :roles => :app do
|
48
|
+
username = user || ENV['USER']
|
49
|
+
rails_root = Dir.pwd # You have to run cap tasks from RAILS_ROOT anyways
|
50
|
+
execute_on_servers do |server|
|
51
|
+
`rsync -r -p -v -e \"ssh -i #{ssh_options[:keys]}\" #{File.join(rails_root, 'public', 'bin')}/ #{username}@#{server}:#{File.join(shared_path, 'flex_files')}/`
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
task :make_symlink, :roles => :app do
|
56
|
+
run "ln -s #{shared_path}/flex_files #{release_path}/public/bin"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Adds a little helper to make it easier empbedding SWFs in ERB templates.
|
2
|
+
module SWFHelper
|
3
|
+
|
4
|
+
# Creates a swfObject Javascript call. You must include swfobject.js to use this.
|
5
|
+
# See http://code.google.com/p/swfobject/wiki/documentation for full details and documentation
|
6
|
+
# of the swfobject js library.
|
7
|
+
def swfobject(swf_url, params = {})
|
8
|
+
params.reverse_merge!({:width => '100%',
|
9
|
+
:height => '100%',
|
10
|
+
:id => 'flashContent',
|
11
|
+
:version => '9.0.0',
|
12
|
+
:express_install_swf => '/expressInstall.swf',
|
13
|
+
:flash_vars => nil,
|
14
|
+
:params => nil,
|
15
|
+
:attributes => nil,
|
16
|
+
:create_div => false,
|
17
|
+
:include_authenticity_token => true,
|
18
|
+
:include_session_token => true
|
19
|
+
})
|
20
|
+
arg_order = [:id, :width, :height, :version, :express_install_swf]
|
21
|
+
js_params = ["'#{swf_url}?#{rails_asset_id(swf_url)}'"]
|
22
|
+
js_params += arg_order.collect {|arg| "'#{params[arg]}'" }
|
23
|
+
|
24
|
+
# Add authenticity_token and the session key to flashVars. This will only work if flashVars is a Hash or nil
|
25
|
+
# If it's a string representing the name of a Javascript variable, then you need to add them yourself
|
26
|
+
# like this:
|
27
|
+
# <script>
|
28
|
+
# ... other code that defines flashVars and sets some of its parameters
|
29
|
+
# flashVars['authenticity_token'] = <%= form_authenticity_token -%>
|
30
|
+
# flashVars['session_token'] = <%= session.session_id -%>
|
31
|
+
# </script>
|
32
|
+
# If you include an authenticity_token parameter in flashVars,
|
33
|
+
# then the Flex app will add it to Rx.defaultMetadata, so that it will be sent
|
34
|
+
# back up to your Rails app with every request.
|
35
|
+
params[:flash_vars] ||= {}
|
36
|
+
if params[:flash_vars].is_a?(Hash)
|
37
|
+
if params[:include_authenticity_token] && ActionController::Base.allow_forgery_protection
|
38
|
+
params[:flash_vars].reverse_merge!(:authenticity_token => form_authenticity_token)
|
39
|
+
end
|
40
|
+
if params[:include_session_token]
|
41
|
+
params[:flash_vars].reverse_merge!(:session_token => session.session_id)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
js_params += [params[:flash_vars], params[:params], params[:attributes]].collect do |hash_or_string|
|
46
|
+
if hash_or_string.is_a?(Hash)
|
47
|
+
hash_or_string.to_json
|
48
|
+
else # If it's not a hash, then it should be a string giving the name of the Javascript variable to use
|
49
|
+
hash_or_string
|
50
|
+
end
|
51
|
+
end.compact
|
52
|
+
|
53
|
+
swf_tag = javascript_tag do
|
54
|
+
"swfobject.embedSWF(#{js_params.join(',')})"
|
55
|
+
end
|
56
|
+
swf_tag += content_tag(:div, nil, :id => params[:id]) if params[:create_div]
|
57
|
+
swf_tag
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|