restfulie 0.6.0 → 0.7.0

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.
Files changed (74) hide show
  1. data/README.textile +83 -7
  2. data/Rakefile +98 -13
  3. data/lib/restfulie/client/base.rb +48 -53
  4. data/lib/restfulie/client/configuration.rb +69 -0
  5. data/lib/restfulie/client/http/adapter.rb +487 -0
  6. data/lib/restfulie/client/http/atom_ext.rb +87 -0
  7. data/lib/restfulie/client/http/cache.rb +28 -0
  8. data/lib/restfulie/client/http/error.rb +80 -0
  9. data/lib/restfulie/client/http/marshal.rb +147 -0
  10. data/lib/restfulie/client/http.rb +13 -0
  11. data/lib/restfulie/client.rb +8 -56
  12. data/lib/restfulie/common/builder/builder_base.rb +58 -0
  13. data/lib/restfulie/common/builder/helpers.rb +22 -0
  14. data/lib/restfulie/common/builder/marshalling/atom.rb +197 -0
  15. data/lib/restfulie/common/builder/marshalling/base.rb +12 -0
  16. data/lib/restfulie/common/builder/marshalling/json.rb +2 -0
  17. data/lib/restfulie/common/builder/marshalling.rb +16 -0
  18. data/lib/restfulie/common/builder/rules/collection_rule.rb +10 -0
  19. data/lib/restfulie/common/builder/rules/link.rb +20 -0
  20. data/lib/restfulie/common/builder/rules/links.rb +9 -0
  21. data/lib/restfulie/common/builder/rules/member_rule.rb +8 -0
  22. data/lib/restfulie/common/builder/rules/namespace.rb +25 -0
  23. data/lib/restfulie/common/builder/rules/rules_base.rb +76 -0
  24. data/lib/restfulie/common/builder.rb +16 -0
  25. data/lib/restfulie/common/errors.rb +9 -0
  26. data/lib/restfulie/{logger.rb → common/logger.rb} +3 -5
  27. data/lib/restfulie/common/representation/atom.rb +48 -0
  28. data/lib/restfulie/common/representation/generic.rb +33 -0
  29. data/lib/restfulie/common/representation/xml.rb +24 -0
  30. data/lib/restfulie/common/representation.rb +10 -0
  31. data/lib/restfulie/common.rb +23 -0
  32. data/lib/restfulie/server/action_controller/base.rb +31 -0
  33. data/lib/restfulie/server/action_controller/params_parser.rb +62 -0
  34. data/lib/restfulie/server/action_controller/restful_responder.rb +39 -0
  35. data/lib/restfulie/server/action_controller/routing/restful_route.rb +14 -0
  36. data/lib/restfulie/server/action_controller/routing.rb +12 -0
  37. data/lib/restfulie/server/action_controller.rb +15 -0
  38. data/lib/restfulie/server/action_view/helpers.rb +45 -0
  39. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +15 -0
  40. data/lib/restfulie/server/action_view/template_handlers.rb +13 -0
  41. data/lib/restfulie/server/action_view.rb +8 -0
  42. data/lib/restfulie/server/configuration.rb +21 -0
  43. data/lib/restfulie/server/core_ext/array.rb +45 -0
  44. data/lib/restfulie/server/core_ext.rb +1 -0
  45. data/lib/restfulie/server/restfulie_controller.rb +1 -17
  46. data/lib/restfulie/server.rb +15 -0
  47. data/lib/restfulie.rb +4 -72
  48. data/lib/vendor/atom/configuration.rb +24 -0
  49. data/lib/vendor/atom/pub.rb +250 -0
  50. data/lib/vendor/atom/xml/parser.rb +373 -0
  51. data/lib/vendor/atom.rb +771 -0
  52. metadata +94 -33
  53. data/lib/restfulie/client/atom_media_type.rb +0 -75
  54. data/lib/restfulie/client/cache.rb +0 -103
  55. data/lib/restfulie/client/entry_point.rb +0 -94
  56. data/lib/restfulie/client/extensions/http.rb +0 -116
  57. data/lib/restfulie/client/helper.rb +0 -28
  58. data/lib/restfulie/client/instance.rb +0 -158
  59. data/lib/restfulie/client/request_execution.rb +0 -321
  60. data/lib/restfulie/client/state.rb +0 -36
  61. data/lib/restfulie/media_type.rb +0 -143
  62. data/lib/restfulie/media_type_control.rb +0 -115
  63. data/lib/restfulie/media_type_defaults.rb +0 -51
  64. data/lib/restfulie/server/atom_media_type.rb +0 -115
  65. data/lib/restfulie/server/base.rb +0 -91
  66. data/lib/restfulie/server/controller.rb +0 -122
  67. data/lib/restfulie/server/instance.rb +0 -102
  68. data/lib/restfulie/server/marshalling.rb +0 -47
  69. data/lib/restfulie/server/opensearch/description.rb +0 -54
  70. data/lib/restfulie/server/opensearch.rb +0 -18
  71. data/lib/restfulie/server/transition.rb +0 -93
  72. data/lib/restfulie/unmarshalling.rb +0 -131
  73. data/lib/vendor/jeokkarak/hashi.rb +0 -65
  74. data/lib/vendor/jeokkarak/jeokkarak.rb +0 -81
@@ -0,0 +1,76 @@
1
+ module Restfulie::Common::Builder::Rules; end
2
+
3
+ class Restfulie::Common::Builder::Rules::Base
4
+ attr_accessor :blocks
5
+ attr_accessor :links
6
+ attr_reader :namespaces
7
+
8
+ def initialize(blocks = [], &block)
9
+ @links = Restfulie::Common::Builder::Rules::Links.new
10
+ @blocks = (block_given? ? [block] : []) + blocks
11
+ @namespaces = []
12
+ end
13
+
14
+ def apply(*args)
15
+ @blocks.each do |block|
16
+ params = ([self] + args)[0..block.arity-1]
17
+ block.call(*params)
18
+ end
19
+ end
20
+
21
+ # Use to register namespace
22
+ #
23
+ #==Example:
24
+ #
25
+ # namespace(@album , "http://example.com")
26
+ # namespace(:albums, "http://example.com")
27
+ # namespace(:albums, "http://example.com", :eager_load => false)
28
+ # namespace(:albums, "http://example.com", :eager_load => { :title => 'A title' })
29
+ #
30
+ def namespace(ns, uri = nil, options = {}, &block)
31
+ object = nil
32
+
33
+ if !ns.kind_of?(String) && !ns.kind_of?(Symbol)
34
+ object = ns
35
+ ns = object.class.to_s.demodulize.downcase.pluralize.to_sym
36
+ options[:eager_load] = true unless options.key?(:eager_load)
37
+ end
38
+
39
+ unless [true, false, nil].include?(options[:eager_load])
40
+ object = options[:eager_load]
41
+ options[:eager_load] = true
42
+ end
43
+
44
+ namespace = find_or_new_namespace(ns, uri)
45
+ eager_load(object, namespace) if options[:eager_load]
46
+
47
+ yield(namespace) if block_given?
48
+ namespace
49
+ end
50
+
51
+ def metaclass
52
+ (class << self; self; end)
53
+ end
54
+
55
+ private
56
+ # Load attributes of the object to passed hash.
57
+ # If object respond to attributes, attributes is merge, unless merge instance variables
58
+ def eager_load(object, ns)
59
+ if object.kind_of?(Hash)
60
+ ns.merge!(object.symbolize_keys)
61
+ elsif object.respond_to?(:attributes)
62
+ ns.merge!(object.attributes.symbolize_keys)
63
+ else
64
+ object.instance_variables.each do |var|
65
+ ns[var.gsub(/^@/, '').to_sym] = object.instance_variable_get(var)
66
+ end
67
+ end
68
+ end
69
+
70
+ # Search a namespace or create a new
71
+ def find_or_new_namespace(name, uri)
72
+ namespace = @namespaces.find { |n| n.namespace == name } || (@namespaces << Restfulie::Common::Builder::Rules::Namespace.new(name, uri)).last
73
+ namespace.uri = uri unless uri.nil?
74
+ namespace
75
+ end
76
+ end
@@ -0,0 +1,16 @@
1
+ #initialize namespace
2
+ module Restfulie::Common::Builder; end
3
+
4
+ %w(
5
+ helpers
6
+ builder_base
7
+ marshalling
8
+ rules/rules_base
9
+ rules/link
10
+ rules/links
11
+ rules/namespace
12
+ rules/member_rule
13
+ rules/collection_rule
14
+ ).each do |file|
15
+ require File.join(File.dirname(__FILE__), 'builder', file)
16
+ end
@@ -0,0 +1,9 @@
1
+ module Restfulie::Common::Error
2
+ class RestfulieError < StandardError; end
3
+ class MarshallingError < RestfulieError; end
4
+ class UndefinedMarshallingError < MarshallingError; end
5
+
6
+ # Atom marshallinh error
7
+ class AtomMarshallingError < MarshallingError; end
8
+ class NameSpaceError < AtomMarshallingError; end
9
+ end
@@ -1,13 +1,11 @@
1
- module Restfulie
2
-
1
+ module Restfulie::Common::Logger
3
2
  # Configure the logger used by Restfulie
4
3
  #
5
4
  # The logger defaults to ActiveSupport::BufferedLogger.new(STDOUT)
6
5
  class << self
7
6
  attr_accessor :logger
8
7
  end
9
-
10
8
  end
11
9
 
12
- Restfulie.logger = ActiveSupport::BufferedLogger.new(STDOUT)
13
- Restfulie.logger.level = Logger::DEBUG
10
+ Restfulie::Common::Logger.logger = ActiveSupport::BufferedLogger.new(STDOUT)
11
+ Restfulie::Common::Logger.logger.level = Logger::DEBUG
@@ -0,0 +1,48 @@
1
+ module Restfulie::Common::Representation
2
+ # Implements the interface for unmarshal Atom media type responses (application/atom+xml) to ruby objects instantiated by rAtom library.
3
+ #
4
+ # Furthermore, this class extends rAtom behavior to enable client users to easily access link relationships.
5
+ class Atom
6
+
7
+ cattr_reader :media_type_name
8
+ @@media_type_name = 'application/atom+xml'
9
+
10
+ cattr_reader :headers
11
+ @@headers = {
12
+ :get => { 'Accept' => media_type_name },
13
+ :post => { 'Content-Type' => media_type_name }
14
+ }
15
+
16
+ #Convert raw string to rAtom instances (client side)
17
+ def unmarshal(content)
18
+ begin
19
+ ::Atom::Feed.load_feed(content)
20
+ rescue ::ArgumentError
21
+ ::Atom::Entry.load_entry(content)
22
+ end
23
+ end
24
+
25
+ def marshal(string, rel)
26
+ string
27
+ end
28
+
29
+ # transforms this content into a parameter hash for rails (server-side usage)
30
+ def self.to_hash(content)
31
+ Hash.from_xml(content).with_indifferent_access
32
+ end
33
+
34
+ def prepare_link_for(link)
35
+ link
36
+ end
37
+
38
+ def prepare_link_for(link)
39
+ link
40
+ end
41
+
42
+ def prepare_link_for(link)
43
+ link
44
+ end
45
+ end
46
+
47
+ end
48
+
@@ -0,0 +1,33 @@
1
+ module Restfulie::Common::Representation
2
+ # Unknown representation's unmarshalling on the client side
3
+ class Generic
4
+
5
+ def self.media_type_name
6
+ raise Restfulie::Common::Error::RestfulieError.new("Generic representation does not have a specific media type")
7
+ end
8
+
9
+ cattr_reader :headers
10
+ @@headers = {
11
+ :get => { },
12
+ :post => { }
13
+ }
14
+
15
+ # Because there is no media type registered, return the content itself
16
+ def unmarshal(content)
17
+ def content.links
18
+ []
19
+ end
20
+ content
21
+ end
22
+
23
+ def marshal(string, rel)
24
+ string
25
+ end
26
+
27
+ def prepare_link_for(link)
28
+ link
29
+ end
30
+ end
31
+
32
+ end
33
+
@@ -0,0 +1,24 @@
1
+ module Restfulie::Common::Representation
2
+ # Implements the interface for marshal Xml media type requests (application/xml)
3
+ class XmlD
4
+
5
+ cattr_reader :media_type_name
6
+ @@media_type_name = 'application/xml'
7
+
8
+ cattr_reader :headers
9
+ @@headers = {
10
+ :post => { 'Content-Type' => media_type_name }
11
+ }
12
+
13
+ def unmarshal(string)
14
+ raise "should never be invoked, xml to ruby objects should be handled by rails itself"
15
+ end
16
+
17
+ def marshal(string, rel)
18
+ string
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
@@ -0,0 +1,10 @@
1
+ #initialize namespace
2
+ module Restfulie::Common::Representation; end
3
+
4
+ %w(
5
+ atom
6
+ xml
7
+ ).each do |file|
8
+ require File.join(File.dirname(__FILE__), 'representation', file)
9
+ end
10
+
@@ -0,0 +1,23 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ require 'rubygems'
5
+ require 'active_support'
6
+ require 'action_controller'
7
+
8
+ require 'vendor/atom'
9
+
10
+ module Restfulie
11
+ module Common; end
12
+ end
13
+
14
+ %w(
15
+ errors
16
+ logger
17
+ builder
18
+ representation
19
+ ).each do |file|
20
+ require "restfulie/common/#{file}"
21
+ end
22
+
23
+ include ActiveSupport::CoreExtensions::Hash
@@ -0,0 +1,31 @@
1
+ module Restfulie
2
+ module Server
3
+ module ActionController
4
+
5
+ module Base
6
+
7
+ def self.included(base)
8
+ # Sets a default responder for this controller.
9
+ # Needs to require responder_legacy.rb
10
+ base.responder = Restfulie::Server::ActionController::RestfulResponder
11
+ # Atom representation is added by default
12
+ ParamsParser.register('application/atom+xml', Restfulie::Common::Representation::Atom)
13
+ end
14
+
15
+ protected
16
+
17
+ # If your controller inherits from Restfulie::Server::Controller::Base,
18
+ # it will have an :atom option, very similar to render :xml
19
+ def render(options = {}, extra_options = {}, &block)
20
+ if atom = options[:atom]
21
+ response.content_type ||= Mime::ATOM
22
+ render_for_text(atom.respond_to?(:to_atom) ? atom.to_atom.to_xml : atom.to_xml, options[:status])
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ module Restfulie
2
+ module Server
3
+ module ActionController
4
+ class ParamsParser
5
+ # This class is just a proxy for the extension point offered by ActionController::Base
6
+ @@param_parsers = ::ActionController::Base.param_parsers
7
+
8
+ ##
9
+ # :singleton-method:
10
+ # Use it to register param parsers on the server side.
11
+ #
12
+ # * <tt>media type</tt>
13
+ # * <tt>a restfulie representation with to_hash method</tt>
14
+ #
15
+ # Restfulie::Server::ActionController::ParamsParser.register('application/atom+xml', Atom)
16
+ #
17
+ def self.register(content_type, representation)
18
+ @@param_parsers[Mime::Type.lookup(content_type)] = representation.method(:to_hash).to_proc
19
+ end
20
+
21
+ ##
22
+ # :singleton-method:
23
+ # Use it to unregister param parsers on the server side.
24
+ #
25
+ # * <tt>media type</tt>
26
+ #
27
+ # Restfulie::Server::ActionController::ParamsParser.unregister('application/atom+xml')
28
+ #
29
+ def self.unregister(content_type)
30
+ @@param_parsers.delete(Mime::Type.lookup(content_type))
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # This monkey patch is needed because Rails 2.3.5 doesn't support
38
+ # a way of use rescue_from ActionController handling to return
39
+ # bad request status when trying to parse an invalid body request
40
+ #
41
+ # In Rails 3 this won't be necessary, because all exception handling
42
+ # extensions are handled by the Rack stack
43
+ #
44
+ # TODO Change this when porting this code to Rails 3
45
+ ::ActionController::ParamsParser.class_eval do
46
+ def call(env)
47
+ begin
48
+ if params = parse_formatted_parameters(env)
49
+ env["action_controller.request.request_parameters"] = params
50
+ else
51
+ if env["CONTENT_LENGTH"] && (env["CONTENT_LENGTH"] != "0")
52
+ return [415, {'Content-Type' => 'text/html'}, "<html><body><h1>415 Unsupported Media Type</h1></body></html>"]
53
+ end
54
+ end
55
+ rescue
56
+ return [400, {'Content-Type' => 'text/html'}, "<html><body><h1>400 Bad Request</h1></body></html>"]
57
+ end
58
+
59
+ @app.call(env)
60
+ end
61
+ end
62
+
@@ -0,0 +1,39 @@
1
+ module Restfulie::Server::ActionController
2
+ class RestfulResponder < ActionController::Responder
3
+
4
+ def to_format
5
+ return if do_http_cache? && do_http_cache!
6
+ super
7
+ end
8
+
9
+ protected
10
+ def do_http_cache!
11
+ timestamp = resources.flatten.map do |resource|
12
+ (resource.updated_at || Time.now).utc if resource.respond_to?(:updated_at)
13
+ end.compact.max
14
+
15
+ controller.response.last_modified = timestamp if timestamp
16
+ set_public_cache_control!
17
+
18
+ head :not_modified if fresh = request.fresh?(controller.response)
19
+ fresh
20
+ end
21
+
22
+ def do_http_cache?
23
+ get? && @http_cache != false && ActionController::Base.perform_caching &&
24
+ !new_record? && controller.response.last_modified.nil?
25
+ end
26
+
27
+ def new_record?
28
+ resource.respond_to?(:new_record?) && resource.new_record?
29
+ end
30
+
31
+ def set_public_cache_control!
32
+ cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
33
+ cache_control.delete("private")
34
+ cache_control.delete("no-cache")
35
+ cache_control << "public"
36
+ response.headers["Cache-Control"] = cache_control.join(', ')
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ module Restfulie::Server::ActionController::Routing::Route
2
+
3
+ def self.included(base)
4
+ #base.alias_method_chain :extract_request_environment, :host
5
+ end
6
+
7
+ #def extract_request_environment_with_host(request)
8
+ #env = extract_request_environment_without_host(request)
9
+ #env.merge :host => request.host,
10
+ #:domain => request.domain, :subdomain => request.subdomains.first
11
+ #end
12
+
13
+ end
14
+
@@ -0,0 +1,12 @@
1
+ module Restfulie::Server::ActionController::Routing#:nodoc:
2
+ end
3
+
4
+ require 'restfulie/server/action_controller/routing/restful_route'
5
+
6
+ ActionController::Routing::RouteSet.send :include,
7
+ Restfulie::Server::ActionController::Routing::Route
8
+
9
+ ActionController::Routing::Route.send :include,
10
+ Restfulie::Server::ActionController::Routing::Route
11
+
12
+
@@ -0,0 +1,15 @@
1
+ module Restfulie::Server::ActionController#:nodoc:
2
+
3
+ if defined?(::ActionController) || defined?(::ApplicationController)
4
+
5
+ %w(
6
+ params_parser
7
+ restful_responder
8
+ base
9
+ routing
10
+ ).each do |file|
11
+ autoload file.camelize.to_sym, "restfulie/server/action_controller/#{file}"
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ module Restfulie::Server::ActionView::Helpers
2
+ # Load a partial template to execute in describe
3
+ #
4
+ # For example:
5
+ #
6
+ # Passing the current context to partial in template:
7
+ #
8
+ # describe_member(@album) do |member, album|
9
+ # partial('member', binding)
10
+ # end
11
+ #
12
+ # in partial:
13
+ #
14
+ # member.links << link(:rel => :artistis, :href => album_artists_url(album))
15
+ #
16
+ # Or passing local variables assing
17
+ #
18
+ # descirbe_collection(@albums) do |collection|
19
+ # collection.describe_members do |member, album|
20
+ # partial('member', :locals => {:member => member, :album => album})
21
+ # end
22
+ # end
23
+ #
24
+ def partial(partial_path, caller_binding = nil)
25
+ template = _pick_partial_template(partial_path)
26
+
27
+ # Create a context to assing variables
28
+ if caller_binding.kind_of?(Hash)
29
+ Proc.new do
30
+ extend Restfulie::Common::Builder::Helpers
31
+ context = eval("(class << self; self; end)", binding)
32
+
33
+ unless caller_binding[:locals].nil?
34
+ caller_binding[:locals].each do |k, v|
35
+ context.send(:define_method, k.to_sym) { v }
36
+ end
37
+ end
38
+
39
+ partial(partial_path, binding)
40
+ end.call
41
+ else
42
+ eval(template.source, caller_binding, template.path)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ module Restfulie::Server::ActionView::TemplateHandlers
2
+
3
+ class Tokamak < ActionView::TemplateHandler
4
+ include ActionView::TemplateHandlers::Compilable
5
+
6
+ # TODO: Implement error for code not return builder
7
+ def compile(template)
8
+ "extend Restfulie::Common::Builder::Helpers; " +
9
+ "extend Restfulie::Server::ActionView::Helpers; " +
10
+ "code_block = lambda { #{template.source} };" +
11
+ "builder = code_block.call; " +
12
+ "builder.to_atom "
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Restfulie::Server::ActionView::TemplateHandlers #:nodoc:
2
+ end
3
+
4
+ require 'restfulie/server/action_view/template_handlers/tokamak'
5
+
6
+ if defined? ::ActionView::Template and ::ActionView::Template.respond_to? :register_template_handler
7
+ ::ActionView::Template
8
+ else
9
+ ::ActionView::Base
10
+ end.register_template_handler(:tokamak, Restfulie::Server::ActionView::TemplateHandlers::Tokamak)
11
+
12
+ ::ActionController::Base.exempt_from_layout :tokamak if defined? ::ActionController::Base
13
+
@@ -0,0 +1,8 @@
1
+ if defined? ::ActionView and ::ActionController
2
+
3
+ module Restfulie::Server::ActionView #:nodoc:
4
+ end
5
+
6
+ require 'restfulie/server/action_view/template_handlers'
7
+ require 'restfulie/server/action_view/helpers'
8
+ end
@@ -0,0 +1,21 @@
1
+ module Restfulie::Server::Configuration
2
+ #Defines host to be passed to polymorphic_url.
3
+ # You need to setup this to your own domain in order to generate meaningful links.
4
+ mattr_accessor :host
5
+ @@host = 'localhost'
6
+
7
+ # Passes a symbol to polymorphic_url in order to use a namespaced named_route.
8
+ # So, if config.named_route_prefix = :rest, it will search for rest_album_url,
9
+ # rest_album_songs_url, and so on.
10
+ mattr_accessor :named_route_prefix
11
+ @@named_route_prefix = nil
12
+
13
+ # This defines a Rails-like way to setup options. You can do, in a initializer:
14
+ # Restfulie::Server.setup do |config|
15
+ # config.host = 'mydomain.com'
16
+ # end
17
+ def self.setup
18
+ yield self
19
+ end
20
+ end
21
+
@@ -0,0 +1,45 @@
1
+ # Introspective methods to assist in the conversion of collections in other formats.
2
+ class Array
3
+ def to_atom(options={}, &block)
4
+ raise "Not all elements respond to to_atom" unless all? { |e| e.respond_to? :to_atom }
5
+ options = options.dup
6
+
7
+ if options.delete :only_self_link
8
+ options[:skip_associations_links] = true
9
+ options[:skip_attributes] = true
10
+ end
11
+
12
+ Atom::Feed.new do |feed|
13
+ # TODO: Define better feed attributes
14
+ # Array#to_s can return a very long string
15
+ feed.title = "Collection of #{map {|i| i.class.name }.uniq.to_sentence}"
16
+ # TODO: this id does not comply with Rest standards yet
17
+ feed.id = hash
18
+ feed.updated = updated_at
19
+
20
+ each do |element|
21
+ feed.entries << element.to_atom(options)
22
+ end
23
+
24
+ yield feed if block_given?
25
+ end
26
+ end
27
+
28
+ # Return max update date for items in collection, for it uses the updated_at of items.
29
+ #
30
+ #==Example:
31
+ #
32
+ # Find max updated at in ActiveRecord objects
33
+ #
34
+ # albums = Albums.find(:all)
35
+ # albums.updated_at
36
+ #
37
+ # Using a custom field to check the max date
38
+ #
39
+ # albums = Albums.find(:all)
40
+ # albums.updated_at(:created_at)
41
+ #
42
+ def updated_at(field = :updated_at)
43
+ map { |item| item.send(field) if item.respond_to?(field) }.compact.max || Time.now
44
+ end
45
+ end
@@ -0,0 +1 @@
1
+ require 'restfulie/server/core_ext/array'
@@ -1,25 +1,9 @@
1
- #
2
- # Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
3
- # All rights reserved.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
1
  module Restfulie
19
2
 
20
3
  module Server
21
4
 
22
5
  # Controller which adds default CRUD + search + other operations.
6
+ # TODO: move these actions to controller/base.rb (maybe using InheritedResources, maybe not)
23
7
  module Controller
24
8
 
25
9
  # creates a model based on the request media-type extracted from its content-type
@@ -0,0 +1,15 @@
1
+ require 'restfulie/common'
2
+ require 'responders_backport'
3
+
4
+ module Restfulie::Server; end
5
+
6
+ %w(
7
+ configuration
8
+ action_controller
9
+ action_view
10
+ core_ext
11
+ restfulie_controller
12
+ ).each do |file|
13
+ require "restfulie/server/#{file}"
14
+ end
15
+