/lib/thingfish/filter/yaml.rb
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