joekhoobyar/cardiac

View on GitHub
lib/cardiac/representation.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'mime/types'
require 'uri'
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/object/to_query'
require 'rack/utils'
require 'multi_json'

module Cardiac
  module Representation
    
    # Looking up coders, mimes, etc.
    module LookupMethods
      def coder_for(search)
        search = $1.to_s.classify if search =~ /\.?([a-z][a-z0-9_]*)$/i
        const_get search.to_s
      end

      def mime_types(options={})
        options[:types] || MIME::Types
      end

      def mimes_for(search, options={})
        options = {complete: true, platform: false}.merge!(options)
        case search
        when /\.?([^\/\.])$/
          mime_types(options).of(search.to_s, options[:platform])
        when Symbol
          mime_types(options)[search.to_s, options]
        else
          mime_types(options)[search, options]
        end
      end
    end

    # Basic reflection of a representation type.
    class Reflection < Struct.new(:extension, :types, :default_type, :coder)
      def initialize(extension,default_type=nil,*extra_types)
        types = __codecs__.mimes_for(extension) + extra_types
        if default_type.nil?
          default_type = types.first
        elsif ! types.include? default_type
          types.unshift default_type
        end
        super extension.to_sym, types, default_type, __codecs__.coder_for(extension)
      end
      
      delegate :coder_for, :mimes_for, to: :__codecs__
      private :coder_for, :mimes_for
      
      def matches?(mime_type)
        types.any?{|type| type.like? mime_type}
      end
    
      def __codecs__
        @__codecs__ ||= ::Cardiac::Representation::Codecs
      end
    end

    module Codecs
      extend LookupMethods
      
      module FormEncoded
      module_function
      
        def encode(value,options={})
          String===value ? value : URI.encode_www_form(value)
        end

        def decode(value,options={})
          Hash===value ? value.stringify_keys : Hash[URI.decode_www_form(value)]
        end
      end
      
      module UrlEncoded
        
        # In Ruby 1.9.3, super is not available from module_function(s).
        # It is simplest to just define all extensions here, then.
        module Extensions
          include ::Cardiac::RackUtils
          include FormEncoded
          alias encode_form encode
          alias decode_form decode
        end
        
        include Extensions
        extend Extensions
        
      module_function
      
        def encode(value,options={})
          Hash===value ? build_nested_query(value) : encode_form(value)
        end

        def decode(value,options={})
          decode_form(value).inject({}) do |params,(key,value)|
            normalize_params params, key, value
          end
        end
      end

      module Json
        module_function
        def encode(value,options={})
          MultiJson.dump(value.as_json(options), options) unless value.kind_of?(String)
        end

        def decode(value,options={})
          ::ActiveSupport::JSON.decode(value, options)
        end
      end

      module Xml
        module_function
        def encode(value,options={})
          value.to_xml(options)
        end

        def decode(value,options={})
          Hash.from_xml(value)
        end
      end
    end
  end
end