restfulx 1.2.5 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/README.rdoc +3 -3
  2. data/Rakefile +17 -2
  3. data/VERSION.yml +2 -3
  4. data/bin/rx-gen +1 -1
  5. data/ext/restfulx/ext/amf/serializer/extconf.rb +3 -0
  6. data/lib/restfulx.rb +43 -81
  7. data/lib/restfulx/active_record_tasks.rb +8 -6
  8. data/lib/restfulx/active_record_uuid_helper.rb +9 -10
  9. data/lib/restfulx/amf.rb +14 -0
  10. data/lib/restfulx/amf/class_mapping.rb +106 -0
  11. data/lib/restfulx/amf/ext.rb +11 -0
  12. data/lib/restfulx/amf/ext/serializer.bundle +0 -0
  13. data/lib/restfulx/amf/pure.rb +11 -0
  14. data/lib/restfulx/amf/pure/io_helpers.rb +52 -0
  15. data/lib/restfulx/amf/pure/serializer.rb +304 -0
  16. data/lib/restfulx/configuration.rb +16 -12
  17. data/lib/restfulx/{rails/recipes.rb → recipes.rb} +1 -2
  18. data/lib/restfulx/rx_action_controller.rb +34 -0
  19. data/lib/restfulx/rx_active_record.rb +360 -0
  20. data/lib/restfulx/rx_active_support.rb +139 -0
  21. data/lib/restfulx/{datamapper_foo.rb → rx_datamapper.rb} +0 -2
  22. data/lib/restfulx/{rails/schema_to_yaml.rb → schema_to_rx_yaml.rb} +88 -5
  23. data/lib/restfulx/swf_helper.rb +61 -0
  24. data/lib/restfulx/tasks.rb +5 -3
  25. data/rails_generators/rx_config/rx_config_generator.rb +2 -2
  26. data/rails_generators/rx_config/templates/mainapp.mxml +1 -1
  27. data/rails_generators/rx_config/templates/restfulx.erb +5 -3
  28. data/rails_generators/rx_main_app/rx_main_app_generator.rb +2 -2
  29. data/rails_generators/rx_scaffold/rx_scaffold_generator.rb +7 -7
  30. data/rails_generators/rx_yaml_scaffold/rx_yaml_scaffold_generator.rb +5 -3
  31. data/rxgen_generators/rx_config/rx_config_generator.rb +1 -1
  32. data/test/rails/fixtures/locations.yml +5 -6
  33. data/test/rails/fixtures/notes.yml +5 -15
  34. data/test/rails/fixtures/projects.yml +7 -23
  35. data/test/rails/fixtures/tasks.yml +17 -43
  36. data/test/rails/fixtures/users.yml +7 -11
  37. data/test/rails/helpers/functional_test_helper.rb +5 -4
  38. data/test/rails/helpers/performance_test_helper.rb +5 -0
  39. data/test/rails/helpers/test_helper.rb +27 -0
  40. data/test/rails/helpers/unit_test_helper.rb +3 -15
  41. data/test/rails/test_active_foo.rb +21 -25
  42. data/test/rails/{test_rails_integration_functional.rb → test_notes_controller_functional.rb} +5 -5
  43. data/test/rails/test_serialiazation_performance.rb +32 -0
  44. data/test/rails/test_to_amf.rb +30 -0
  45. data/test/rails/test_to_fxml.rb +18 -15
  46. data/test/rails/test_to_json.rb +2 -14
  47. metadata +30 -19
  48. data/lib/restfulx/active_foo.rb +0 -178
  49. data/lib/restfulx/rails/schema_to_yaml/extensions/enumerable.rb +0 -8
  50. data/lib/restfulx/rails/schema_to_yaml/settings/config.rb +0 -17
  51. data/lib/restfulx/rails/schema_to_yaml/settings/core.rb +0 -73
  52. data/lib/restfulx/rails/swf_helper.rb +0 -59
data/README.rdoc CHANGED
@@ -19,7 +19,7 @@ Here's some of the things you can do with *RestfulX*:
19
19
  that use _ActiveRecord_, _DataMapper_, _CouchRest_, _ActiveCouch_ and so on.
20
20
 
21
21
  * *Communicate* between your Flex/AIR Rich Internet Application and service providers
22
- using either _XML_ or _JSON_.
22
+ using either _AMF_, _XML_ or _JSON_.
23
23
 
24
24
  * *Persist* your data directly in Adobe AIR _SQLite_ database or _CouchDB_
25
25
  without any additional infrastructure or intermediate servers.
@@ -33,7 +33,7 @@ Here's some of the things you can do with *RestfulX*:
33
33
 
34
34
  For details on how to get started with the RestfulX framework refer to:
35
35
 
36
- http://restfulx.org
36
+ http://restfulx.github.com
37
37
 
38
38
  == Getting Involved
39
39
 
@@ -47,4 +47,4 @@ Get involved with the community:
47
47
 
48
48
  == License
49
49
 
50
- Copyright (c) 2008-2009 Dima Berastau and Contributors, released under MIT License
50
+ Copyright (c) 2008-2010 Dima Berastau and Contributors, released under MIT License
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ begin
5
5
  Jeweler::Tasks.new do |gem|
6
6
  gem.name = "restfulx"
7
7
  gem.summary = "RestfulX Framework Code Generation Engine / Rails 2.1+ Integration Support"
8
+ gem.description = "RestfulX: The RESTful Way to develop Adobe Flex and AIR applications"
8
9
  gem.email = "dima.berastau@gmail.com"
9
10
  gem.homepage = "http://restfulx.org"
10
11
  gem.rubyforge_project = "restfulx"
@@ -12,19 +13,33 @@ begin
12
13
  gem.files = FileList["[A-Z]*", "{bin,app_generators,rails_generators,rxgen_generators,lib,test,spec,tasks}/**/*"]
13
14
  gem.files.exclude 'test/**/*.log', 'test/**/*.sqlite3'
14
15
  gem.test_files.exclude 'test/**/*.log', 'test/**/*.sqlite3'
15
- gem.add_dependency('rubigen', '>= 1.5.0')
16
+ gem.add_dependency('rubigen', '>= 1.5.2')
16
17
  gem.add_dependency('activesupport', '>=2.0.0')
17
18
  end
19
+
20
+ Jeweler::RubyforgeTasks.new do |rubyforge|
21
+ rubyforge.doc_task = "rdoc"
22
+ end
18
23
  rescue LoadError
19
24
  puts "jeweler not available. Install it with: sudo gem install jeweler"
20
25
  end
21
26
 
27
+ require 'rake/extensiontask'
28
+ Rake::ExtensionTask.new do |ext|
29
+ ext.name = 'serializer'
30
+ ext.gem_spec = Rake.application.jeweler_tasks.gemspec
31
+ # ext.cross_compile = true
32
+ # ext.cross_platform = %w[i386-mswin32 i386-mingw32]
33
+ ext.ext_dir = 'ext/restfulx/ext/amf/serializer'
34
+ ext.lib_dir = 'lib/restfulx/amf/ext'
35
+ end
36
+
22
37
  require 'rake/rdoctask'
23
38
  Rake::RDocTask.new do |rdoc|
24
39
  config = YAML.load(File.read('VERSION.yml'))
25
40
  rdoc.rdoc_dir = 'doc/api'
26
41
  rdoc.title = "RestfulX #{config[:major]}.#{config[:minor]}.#{config[:patch]}"
27
- rdoc.options << '--line-numbers' << '--inline-source' #<< '-Tjamis'
42
+ rdoc.options << '--line-numbers' << '--inline-source' # << '-Tjamis'
28
43
  rdoc.rdoc_files.include('README*')
29
44
  rdoc.rdoc_files.include('lib/**/*.rb')
30
45
  end
data/VERSION.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  ---
2
- :patch: 5
3
- :build:
4
2
  :major: 1
5
- :minor: 2
3
+ :minor: 3
4
+ :patch: 0
data/bin/rx-gen CHANGED
@@ -22,7 +22,7 @@ require 'rubigen'
22
22
  require File.join(File.dirname(__FILE__), '..', 'lib', 'restfulx')
23
23
 
24
24
  if %w(-v --version).include? ARGV.first
25
- puts "#{File.basename($0)} #{RestfulX::FRAMEWORK_VERSION}"
25
+ puts "#{File.basename($0)} #{RestfulX::VERSION}"
26
26
  exit(0)
27
27
  end
28
28
 
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile 'restfulx/ext/amf/serializer'
data/lib/restfulx.rb CHANGED
@@ -1,90 +1,52 @@
1
- # Sets up all the relevant configuration options and brings together
2
- # patches for Rails, Merb, ActiveRecord and Data Mapper.
3
- #
4
- # Loads RestfulX specific rake tasks if appropriate.
5
- module RestfulX
6
-
7
- # :stopdoc:
8
- FRAMEWORK_VERSION = '1.2.5'
9
- LIB_DIR = File.join(File.dirname(__FILE__), 'restfulx/')
10
- # :startdoc:
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+ require 'yaml'
3
+ require 'restfulx/configuration'
11
4
 
12
- # Utility method used to require all files ending in .rb that lie in the
13
- # directory below this file that has the same name as the filename passed
14
- # in. Optionally, a specific _directory_ name can be passed in such that
15
- # the _filename_ does not have to be equivalent to the directory.
16
- #
17
- def self.require_all_libs_relative_to( fname, dir = nil )
18
- dir ||= ::File.basename(fname, '.*')
19
- search_me = ::File.expand_path(
20
- ::File.join(::File.dirname(fname), dir, '*', '*.rb'))
21
-
22
- Dir.glob(search_me).sort.each {|rb| require rb}
5
+ # Settings
6
+ module RestfulX
7
+ # Valid types supported internally on top of standard Rails types
8
+ module Types
9
+ APPLICATION_FXML = 'application/xml'.freeze
10
+ APPLICATION_AMF = 'application/x-amf'.freeze
11
+ end
12
+
13
+ # get the currently defined AMF serializer
14
+ def self.amf_serializer
15
+ @amf_serializer
16
+ end
17
+
18
+ # set the amf serializer to use
19
+ # valid options are :native and :pure, using :pure is recommended as it is as fast
20
+ # as native but currently better tested/supported
21
+ def self.amf_serializer=(value)
22
+ @amf_serializer = value
23
23
  end
24
- end
25
24
 
26
- require RestfulX::LIB_DIR + 'configuration'
25
+ VERSION_SOURCE = YAML.load(File.read(File.join(File.dirname(__FILE__), '..', 'VERSION.yml')))
26
+ VERSION = "#{VERSION_SOURCE[:major]}.#{VERSION_SOURCE[:minor]}.#{VERSION_SOURCE[:patch]}"
27
+ end
27
28
 
28
- # make sure we're running inside Merb
29
- if defined?(Merb::Plugins)
30
- Merb::Plugins.add_rakefiles RestfulX::LIB_DIR + 'tasks'
29
+ # ActiveRecord extensions
30
+ if defined?(ActiveRecord::Base)
31
+ ['rx_active_support', 'rx_active_record'].each { |lib| require "restfulx/#{lib}" }
32
+ ActiveRecord::Base.send :include,
33
+ RestfulX::ActiveRecord unless ActiveRecord::Base.included_modules.include?(RestfulX::ActiveRecord)
34
+ end
31
35
 
32
- Merb::BootLoader.before_app_loads do
33
-
34
- if defined?(ActiveRecord::Base)
35
- Merb.add_mime_type(:fxml, :to_fxml, %w[application/xml text/xml application/x-xml], :charset => "utf-8")
36
- ['active_foo', 'active_record_default_methods'].each { |lib| require RestfulX::LIB_DIR + lib }
37
- Merb::Plugins.add_rakefiles RestfulX::LIB_DIR + 'active_record_tasks'
38
- else
39
- Merb.add_mime_type(:fxml, :to_xml, %w[application/xml text/xml application/x-xml], :charset => "utf-8")
40
- if defined?(Merb::Orms::DataMapper)
41
- require RestfulX::LIB_DIR + 'datamapper_foo'
42
- end
43
- end
44
- end
45
- elsif defined?(ActionController::Base)
46
- # if we are not running in Merb, try to hook up Rails
47
- Mime::Type.register_alias "application/xml", :fxml
36
+ # ActionController/ActionView extensions
37
+ if defined?(ActionController::Base)
38
+ Mime::Type.register_alias RestfulX::Types::APPLICATION_FXML, :fxml
39
+ Mime::Type.register RestfulX::Types::APPLICATION_AMF, :amf
48
40
 
49
- ['active_foo', 'rails/swf_helper', 'rails/schema_to_yaml'].each { |lib| require RestfulX::LIB_DIR + lib }
50
-
51
- ActionView::Base.send :include, SWFHelper unless ActionView::Base.included_modules.include?(SWFHelper)
52
- ActiveRecord::Migration.send :include, SchemaToYaml
41
+ ['rx_action_controller', 'swf_helper'].each { |lib| require "restfulx/#{lib}" }
53
42
 
54
- # We mess with default +render+ implementation a bit to add support for expressions
55
- # such as format.fxml { render :fxml => @foo }
56
- module ActionController
57
- # Override render to add support for render :fxml
58
- class Base
59
- alias_method :old_render, :render unless method_defined?(:old_render)
43
+ ActionController::Base.send :include,
44
+ RestfulX::ActionController unless ActionController::Base.included_modules.include?(RestfulX::ActionController)
45
+ ActionView::Base.send :include,
46
+ RestfulX::SWFHelper unless ActionView::Base.included_modules.include?(RestfulX::SWFHelper)
47
+ end
60
48
 
61
- # so that we can have handling for :fxml option and write code like
62
- # format.fxml { render :fxml => @projects }
63
- def render(options = nil, extra_options = {}, &block)
64
- if options.is_a?(Hash) && options[:fxml]
65
- xml = options[:fxml]
66
- response.content_type ||= Mime::XML
67
- render_for_text(xml.respond_to?(:to_fxml) ? xml.to_fxml : xml, options[:status])
68
- else
69
- old_render(options, extra_options, &block)
70
- end
71
- end
72
- end
73
- end
74
-
75
- module ActiveRecord
76
- # ActiveRecord named scopes are computed *before* restfulx gem gets loaded
77
- # this patch addresses that and makes sure +to_fxml+ calls are properly
78
- # delegated
79
- module NamedScope
80
- # make sure we properly delegate +to_fxml+ calls to the proxy
81
- class Scope
82
- delegate :to_fxml, :to => :proxy_found
83
- end
84
- end
85
- end
86
- elsif defined?(DataMapper)
87
- require RestfulX::LIB_DIR + 'datamapper_foo'
88
- elsif defined?(ActiveRecord::Base)
89
- require RestfulX::LIB_DIR + 'active_foo'
49
+ # DataMapper extensions
50
+ if defined?(DataMapper)
51
+ require 'restfulx/rx_datamapper'
90
52
  end
@@ -1,12 +1,14 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
1
3
  # ActiveRecord specific Rake tasks. Namely, nice little extras such as:
2
4
  # - db:mysql:stage
3
5
  # - db:refresh
4
- require File.join(File.dirname(__FILE__), 'tasks')
5
- require File.join(File.dirname(__FILE__), 'rails', 'schema_to_yaml')
6
+ require 'tasks'
7
+ require 'schema_to_rx_yaml'
6
8
 
7
9
  # stores local copy of the application environment ('production', 'test', etc)
8
10
  # so that appropriate values in config/database.yml are used
9
- APP_ENV = defined?(ENV['RAILS_ENV']) ? ENV['RAILS_ENV'] : ENV['MERB_ENV']
11
+ APP_ENV = ENV['RAILS_ENV']
10
12
 
11
13
  namespace :db do
12
14
  namespace :mysql do
@@ -82,9 +84,9 @@ namespace :db do
82
84
 
83
85
  # used to analyze your schema and dump out a model.yml file for converting old rails projects
84
86
  namespace :schema do
85
- desc "Create model.yml from schema.rb"
86
- task :to_yaml => :environment do
87
- SchemaToYaml.schema_to_yaml
87
+ desc "Create RestfulX model.yml from schema.rb"
88
+ task :to_rx_yaml => :environment do
89
+ SchemaToRxYaml.schema_to_rx_yaml
88
90
  end
89
91
  end
90
92
  end
@@ -2,16 +2,15 @@
2
2
  require 'uuidtools'
3
3
 
4
4
  # Extends ActiveRecord models with UUID based IDs
5
- module RestfulX
6
- module UUIDHelper
7
- def self.included(base)
8
- base.class_eval do
9
- before_create :generate_uuid
10
- end
11
- end
12
-
13
- def generate_uuid
14
- self.id = UUIDTools::UUID.random_create.to_s.gsub("-", "") unless self.id
5
+ module RestfulX::UUIDHelper
6
+ def self.included(base)
7
+ base.class_eval do
8
+ before_create :generate_uuid
15
9
  end
16
10
  end
11
+
12
+ # generates new UUID for the record
13
+ def generate_uuid
14
+ self.id = UUIDTools::UUID.random_create.to_s.gsub("-", "") unless self.id
15
+ end
17
16
  end
@@ -0,0 +1,14 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+ require 'amf/class_mapping'
3
+
4
+ # implements ruby-side AMF support for RestfulX
5
+ module RestfulX::AMF
6
+
7
+ ClassMapper = RestfulX::AMF::ClassMapping.new
8
+
9
+ begin
10
+ require RestfulX.amf_serializer == :native ? 'amf/ext' : 'amf/pure'
11
+ rescue LoadError
12
+ require 'amf/pure'
13
+ end
14
+ end
@@ -0,0 +1,106 @@
1
+ module RestfulX::AMF
2
+ class ClassMapping
3
+ class MappingSet
4
+ attr_accessor :default_as_prefix
5
+
6
+ def initialize #:nodoc:
7
+ @as_mappings = {}
8
+ @ruby_mappings = {}
9
+ @default_as_prefix = ""
10
+ end
11
+
12
+ # Map a given AS class to a ruby class.
13
+ #
14
+ # Use fully qualified names for both.
15
+ #
16
+ # Example:
17
+ #
18
+ # m.map :as 'com.example.Date', :ruby => 'Example::Date'
19
+ def map(params)
20
+ [:as, :ruby].each {|k| params[k] = params[k].to_s if params[k] } # Convert params to strings
21
+
22
+ if params.key?(:as) and params.key?(:ruby)
23
+ @as_mappings[params[:as]] = params[:ruby]
24
+ @ruby_mappings[params[:ruby]] = params[:as]
25
+ end
26
+
27
+ if params.key?(:as)
28
+ params[:ruby] = get_ruby_class_name(params[:as])
29
+ end
30
+ end
31
+
32
+ # Returns the AS class name for the given ruby class name, returing nil if
33
+ # not found
34
+ def get_as_class_name(class_name) #:nodoc:
35
+ unless as_class_name = @ruby_mappings[class_name.to_s]
36
+ as_class_name = "#{@default_as_prefix}.#{class_name}"
37
+ @as_mappings[as_class_name] = class_name.to_s
38
+ @ruby_mappings[class_name.to_s] = as_class_name
39
+ end
40
+ as_class_name
41
+ end
42
+
43
+ # Returns the ruby class name for the given AS class name, returing nil if
44
+ # not found
45
+ def get_ruby_class_name(class_name) #:nodoc:
46
+ unless ruby_class_name = @as_mappings[class_name.to_s]
47
+ ruby_class_name = class_name.sub("#{default_as_prefix}.", "")
48
+ @ruby_mappings[ruby_class_name] = class_name.to_s
49
+ @as_mappings[class_name.to_s] = ruby_class_name
50
+ end
51
+ ruby_class_name
52
+ end
53
+ end
54
+
55
+ # Define class mappings in the block. Block is passed a MappingSet object as
56
+ # the first parameter.
57
+ #
58
+ # Example:
59
+ #
60
+ # RestfulX::AMF::ClassMapper.define do |m|
61
+ # m.map :as => 'AsClass', :ruby => 'RubyClass'
62
+ # end
63
+ def define #:yields: mapping_set
64
+ yield mappings
65
+ end
66
+
67
+ # Return default ActionScript prefix to use. This is recommended compared to
68
+ # defining mappings manually
69
+ def default_as_prefix
70
+ mappings.default_as_prefix
71
+ end
72
+
73
+ # Set the default ActionScript prefix (typically a package e.g. com.foobar) to
74
+ # use for all models
75
+ def default_as_prefix=(value)
76
+ mappings.default_as_prefix = value
77
+ end
78
+
79
+ # Returns the AS class name for the given ruby object. Will also take a string
80
+ # containing the ruby class name
81
+ def get_as_class_name(obj)
82
+ # Get class name
83
+ if obj.is_a?(String)
84
+ ruby_class_name = obj
85
+ else
86
+ ruby_class_name = obj.class.name
87
+ end
88
+
89
+ if obj.respond_to?(:unique_id)
90
+ mappings.get_as_class_name(ruby_class_name)
91
+ else
92
+ nil
93
+ end
94
+ end
95
+
96
+ # Return ruby model class name for a given ActionScript model class name
97
+ def get_ruby_class_name(as_class_name)
98
+ mappings.get_ruby_class_name(as_class_name.to_s)
99
+ end
100
+
101
+ private
102
+ def mappings
103
+ @mappings ||= MappingSet.new
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,11 @@
1
+ require 'restfulx/amf/ext/serializer'
2
+
3
+ module RestfulX::AMF #:nodoc:
4
+ # This module holds all the modules/classes that implement AMF's
5
+ # functionality in native C code
6
+ module Ext
7
+ $DEBUG and warn "Using native extension for AMF."
8
+ end
9
+
10
+ include RestfulX::AMF::Ext
11
+ end
Binary file
@@ -0,0 +1,11 @@
1
+ require 'amf/pure/serializer'
2
+
3
+ module RestfulX::AMF #:nodoc:
4
+ # This module holds all the modules/classes that implement AMF's
5
+ # functionality in pure ruby.
6
+ module Pure
7
+ $DEBUG and warn "Using pure library for AMF."
8
+ end
9
+
10
+ include RestfulX::AMF::Pure
11
+ end
@@ -0,0 +1,52 @@
1
+ module RestfulX::AMF::Pure
2
+ module WriteIOHelpers #:nodoc:
3
+ def pack_integer(integer)
4
+ integer = integer & 0x1fffffff
5
+ if(integer < 0x80)
6
+ [integer].pack('c')
7
+ elsif(integer < 0x4000)
8
+ [integer >> 7 & 0x7f | 0x80].pack('c')+
9
+ [integer & 0x7f].pack('c')
10
+ elsif(integer < 0x200000)
11
+ [integer >> 14 & 0x7f | 0x80].pack('c') +
12
+ [integer >> 7 & 0x7f | 0x80].pack('c') +
13
+ [integer & 0x7f].pack('c')
14
+ else
15
+ [integer >> 22 & 0x7f | 0x80].pack('c')+
16
+ [integer >> 15 & 0x7f | 0x80].pack('c')+
17
+ [integer >> 8 & 0x7f | 0x80].pack('c')+
18
+ [integer & 0xff].pack('c')
19
+ end
20
+ end
21
+
22
+ def pack_double(double)
23
+ [double].pack('G')
24
+ end
25
+
26
+ def pack_int8(val)
27
+ [val].pack('c')
28
+ end
29
+
30
+ def pack_int16_network(val)
31
+ [val].pack('n')
32
+ end
33
+
34
+ def pack_word32_network(val)
35
+ str = [val].pack('L')
36
+ str.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
37
+ str
38
+ end
39
+
40
+ def byte_order
41
+ if [0x12345678].pack("L") == "\x12\x34\x56\x78"
42
+ :BigEndian
43
+ else
44
+ :LittleEndian
45
+ end
46
+ end
47
+
48
+ def byte_order_little?
49
+ (byte_order == :LittleEndian) ? true : false;
50
+ end
51
+ end
52
+ end