PageRenderTime 36ms CodeModel.GetById 21ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/thingfish/filter/yaml.rb

https://bitbucket.org/laika/thingfish
Ruby | 158 lines | 71 code | 33 blank | 54 comment | 3 complexity | 7b33c91fdff0f9d7cb16ee45a1cc0388 MD5 | raw file
Possible License(s): BSD-3-Clause
  1#!/usr/bin/env ruby
  2
  3require 'yaml'
  4
  5require 'thingfish'
  6require 'thingfish/mixins'
  7require 'thingfish/constants'
  8require 'thingfish/acceptparam'
  9require 'thingfish/filter'
 10
 11
 12# A YAML-conversion filter for ThingFish. It converts Ruby objects in the body of responses
 13# to YAML if the client accepts 'text/x-yaml'.
 14#
 15# == Synopsis
 16#
 17#   plugins:
 18#       filters:
 19#          yaml: ~
 20#
 21# == Version
 22#
 23#  $Id$
 24#
 25# == Authors
 26#
 27# * Michael Granger <ged@FaerieMUD.org>
 28# * Mahlon E. Smith <mahlon@martini.nu>
 29#
 30# :include: LICENSE
 31#
 32#---
 33#
 34# Please see the file LICENSE in the top-level directory for licensing details.
 35#
 36class ThingFish::YAMLFilter < ThingFish::Filter
 37	include ThingFish::Loggable,
 38	        ThingFish::Constants
 39
 40	# VCS Revision
 41	VCSRev = %q$Rev$
 42
 43	# The Array of types this filter is interested in
 44	HANDLED_TYPES = [ ThingFish::AcceptParam.parse(RUBY_MIMETYPE) ]
 45	HANDLED_TYPES.freeze
 46
 47	# The YAML mime type.
 48	YAML_MIMETYPE = 'text/x-yaml'
 49	YAML_MIMETYPE.freeze
 50
 51
 52	#################################################################
 53	###	I N S T A N C E   M E T H O D S
 54	#################################################################
 55
 56	### Set up a new Filter object
 57	def initialize( options={} ) # :notnew:
 58		super
 59	end
 60
 61
 62	######
 63	public
 64	######w
 65
 66	### Filter incoming requests, converting YAML to native ruby objects.
 67	def handle_request( request, response )
 68
 69		# Only filter if the client sends what we can convert from.
 70		return unless request.content_type &&
 71			request.content_type.downcase == YAML_MIMETYPE
 72
 73		# Absorb errors so filters can continue
 74		begin
 75			self.log.debug "Converting a %s request to %s" %
 76				[ YAML_MIMETYPE, RUBY_MIMETYPE ]
 77			request.body = YAML.load( request.body.read )
 78		rescue RuntimeError, YAML::ParseError => err
 79			self.log.error "%s while attempting to convert %p to a native ruby object: %s" %
 80				[ err.class.name, request.body, err.message ]
 81			self.log.debug err.backtrace.join("\n")
 82		else
 83			request.content_type = RUBY_MIMETYPE
 84		end
 85	end
 86
 87
 88	### Convert outgoing ruby object responses into YAML.
 89	def handle_response( response, request )
 90
 91		# Only filter if the client wants what we can convert to, and the response body
 92		# is something we know how to convert
 93		return unless request.explicitly_accepts?( YAML_MIMETYPE ) &&
 94			self.accept?( response.content_type )
 95
 96		# Errors converting to yaml should result in a 500.
 97		self.log.debug "Converting a %s response to text/x-yaml" %
 98			[ response.content_type ]
 99		response.body = self.stringify_members( response.body ).to_yaml
100		response.content_type = YAML_MIMETYPE
101	end
102
103
104	### Return an Array of ThingFish::AcceptParam objects which describe which content types
105	### the filter is interested in. The default returns */*, which indicates that it is
106	### interested in all requests/responses.
107	def handled_types
108		return HANDLED_TYPES
109	end
110
111
112	### Returns a Hash of information about the filter; this is of the form:
113	###   {
114	###     'version'  => [ 0, 60 ],               # YAML.rb version
115	###     'supports' => [ [1,0], [1,1] ],        # Supported YAML versions
116	###     'rev'      => 460,                     # VCS rev of plugin
117	###   }
118	def info
119		yaml_rb_version = YAML::VERSION.split('.').collect {|i| Integer(i) }
120		supported_yaml_version = YAML::SUPPORTED_YAML_VERSIONS.collect do |v|
121			v.split('.').collect {|i| Integer(i) }
122		end
123
124		return {
125			'version'  => yaml_rb_version,
126			'supports' => supported_yaml_version,
127			'rev'       => VCSRev[ /: (\w+)/, 1 ] || 0,
128			'accepts'   => [YAML_MIMETYPE],
129			'generates' => [YAML_MIMETYPE],
130		}
131	end
132
133
134
135	#########
136	protected
137	#########
138
139	### Walk over the contents of +data+, stringifying contents.
140	def stringify_members( data )
141		case data
142		when Hash
143			newhash = {}
144			data.each_key {|k| newhash[ k.to_s ] = stringify_members(data[k]) }
145			return newhash
146
147		when Array
148			data.collect {|obj| stringify_members(obj) }
149
150		else
151			data.to_s
152		end
153	end
154
155end # class ThingFish::YAMLFilter
156
157# vim: set nosta noet ts=4 sw=4:
158