base.rb 4.0 KB
Newer Older
1 2 3 4 5
require 'active_resource/connection'

module ActiveResource
  class Base
    class << self
6
      attr_reader :site
J
Jeremy Kemper 已提交
7

8 9
      def site=(site)
        @site = site.is_a?(URI) ? site : URI.parse(site)
10 11 12 13 14 15 16 17 18 19 20 21 22 23
      end

      def connection(refresh = false)
        @connection = Connection.new(site) if refresh || @connection.nil?
        @connection
      end
      
      def element_name
        self.to_s.underscore
      end

      def collection_name
        element_name.pluralize
      end
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

      def prefix(options={})
        default = site.path
        default << '/' unless default[-1..-1] == '/'
        set_prefix default
        prefix(options)
      end
      
      def set_prefix(value = '/')
        prefix_call = value.gsub(/:\w+/) { |s| "\#{options[#{s}]}" }
        method_decl = %(def self.prefix(options={}) "#{prefix_call}" end)
        eval method_decl
      end
      
      def set_element_name(value)
        class << self ; attr_reader :element_name ; end
        @element_name = value
      end
      
      def set_collection_name(value)
        class << self ; attr_reader :collection_name ; end
        @collection_name = value
      end

      def element_path(id, options = {})
        "#{prefix(options)}#{collection_name}/#{id}.xml"
      end
      
      def collection_path(options = {})
        "#{prefix(options)}#{collection_name}.xml"
      end
55
      
56 57
      def primary_key
        set_primary_key 'id'
58 59
      end
      
60 61 62
      def set_primary_key(value)
        class << self ; attr_reader :primary_key ; end
        @primary_key = value
63 64
      end
      
65 66
      # Person.find(1) # => GET /people/1.xml
      # StreetAddress.find(1, :person_id => 1) # => GET /people/1/street_addresses/1.xml
67
      def find(*arguments)
68 69
        scope   = arguments.slice!(0)
        options = arguments.slice!(0) || {}
70 71

        case scope
72 73 74
          when :all   then find_every(options)
          when :first then find_every(options).first
          else             find_single(scope, options)
75 76
        end
      end
77 78 79 80 81 82 83 84 85 86 87

      private
        # { :people => { :person => [ person1, person2 ] } }
        def find_every(options)
          connection.get(collection_path(options)).values.first.values.first.collect { |element| new(element, options) }
        end
        
        # { :person => person1 }
        def find_single(scope, options)
          new(connection.get(element_path(scope, options)).values.first, options)
        end
88 89 90
    end

    attr_accessor :attributes
91
    attr_accessor :prefix_options
92
    
93 94 95
    def initialize(attributes = {}, prefix_options = {})
      @attributes     = attributes
      @prefix_options = prefix_options
96
    end
97 98 99 100 101

    def new_resource?
      id.nil?
    end

102
    def id
103
      attributes[self.class.primary_key]
104 105 106
    end
    
    def id=(id)
107
      attributes[self.class.primary_key] = id
108 109 110
    end
    
    def save
111
      new_resource? ? create : update
112 113 114
    end

    def destroy
115
      connection.delete(self.class.element_path(id, prefix_options)[0..-5])
116 117 118 119 120
    end
    
    def to_xml
      attributes.to_xml(:root => self.class.element_name)
    end
121 122 123 124 125 126 127

    # Reloads the attributes of this object from the remote web service.
    def reload
      @attributes.update(self.class.find(self.id, @prefix_options).instance_variable_get(:@attributes))
      self
    end

128 129 130 131 132 133
    protected
      def connection(refresh = false)
        self.class.connection(refresh)
      end
    
      def update
134
        connection.put(self.class.element_path(id, prefix_options)[0..-5], to_xml)
135
      end
136 137 138 139 140 141 142

      def create
        returning connection.post(self.class.collection_path(prefix_options)[0..-5], to_xml) do |resp|
          self.id = resp['Location'][/\/([^\/]*?)(\.\w+)?$/, 1]
        end
      end

143 144 145 146 147 148 149
      def method_missing(method_symbol, *arguments)
        method_name = method_symbol.to_s
        
        case method_name.last
          when "="
            attributes[method_name.first(-1)] = arguments.first
          when "?"
150
            attributes[method_name.first(-1)] == true
151
          else
152
            attributes.has_key?(method_name) ? attributes[method_name] : super
153 154 155
        end
      end
  end
J
Jeremy Kemper 已提交
156
end