kaiwren-wrest 0.0.6 → 0.0.8
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.
- data/README.rdoc +83 -31
- data/Rakefile +29 -13
- data/VERSION.yml +1 -1
- data/examples/delicious.rb +58 -0
- data/examples/wow_realm_status.rb +57 -0
- data/lib/wrest.rb +11 -2
- data/lib/wrest/components.rb +1 -2
- data/lib/wrest/components/attributes_container.rb +34 -74
- data/lib/wrest/components/attributes_container/typecaster.rb +121 -0
- data/lib/wrest/components/mutators.rb +18 -1
- data/lib/wrest/components/mutators/base.rb +52 -39
- data/lib/wrest/components/mutators/camel_to_snake_case.rb +7 -5
- data/lib/wrest/components/mutators/xml_mini_type_caster.rb +43 -0
- data/lib/wrest/components/mutators/xml_simple_type_caster.rb +22 -20
- data/lib/wrest/components/translators.rb +20 -17
- data/lib/wrest/components/translators/content_types.rb +2 -2
- data/lib/wrest/components/translators/json.rb +11 -8
- data/lib/wrest/components/translators/xml.rb +9 -12
- data/lib/wrest/core_ext/hash/conversions.rb +1 -1
- data/lib/wrest/core_ext/string/conversions.rb +2 -2
- data/lib/wrest/http.rb +24 -0
- data/lib/wrest/http/delete.rb +23 -0
- data/lib/wrest/http/get.rb +23 -0
- data/lib/wrest/http/options.rb +23 -0
- data/lib/wrest/http/post.rb +23 -0
- data/lib/wrest/http/put.rb +23 -0
- data/lib/wrest/http/request.rb +48 -0
- data/lib/wrest/http/response.rb +44 -0
- data/lib/wrest/resource/base.rb +52 -25
- data/lib/wrest/resource/state.rb +6 -0
- data/lib/wrest/uri.rb +85 -29
- data/lib/wrest/uri_template.rb +18 -1
- data/lib/wrest/version.rb +1 -1
- data/spec/spec.opts +1 -1
- data/spec/spec_helper.rb +8 -1
- data/spec/wrest/components/attributes_container/typecaster_spec.rb +63 -0
- data/spec/wrest/components/attributes_container_spec.rb +17 -61
- data/spec/wrest/components/mutators/base_spec.rb +5 -1
- data/spec/wrest/components/mutators/xml_mini_type_caster_spec.rb +75 -0
- data/spec/wrest/components/mutators_spec.rb +21 -0
- data/spec/wrest/components/translators/xml_spec.rb +1 -1
- data/spec/wrest/components/translators_spec.rb +9 -0
- data/spec/wrest/core_ext/string/conversions_spec.rb +9 -0
- data/spec/wrest/http/request_spec.rb +22 -0
- data/spec/wrest/{response_spec.rb → http/response_spec.rb} +4 -4
- data/spec/wrest/resource/base_spec.rb +126 -11
- data/spec/wrest/uri_spec.rb +124 -20
- data/spec/wrest/uri_template_spec.rb +11 -1
- metadata +33 -20
- data/lib/wrest/components/typecast_helpers.rb +0 -41
- data/lib/wrest/response.rb +0 -38
@@ -0,0 +1,121 @@
|
|
1
|
+
# Copyright 2009 Sidu Ponnappa
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
7
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
9
|
+
|
10
|
+
module Wrest
|
11
|
+
module Components::AttributesContainer
|
12
|
+
# An extension to AttributesContainer that adds support for
|
13
|
+
# specifying how the values associated with certain attribute keys
|
14
|
+
# should be typecast.
|
15
|
+
#
|
16
|
+
# This extension can be used in situations where the attributes
|
17
|
+
# hash consists of just strings with no associated tup information.
|
18
|
+
# For example, params recieved from a web browser may contain
|
19
|
+
# attributes like
|
20
|
+
# 'id' => '4', 'dateofbirth' => '1984-04-05'
|
21
|
+
# and we'd like to have these cast to an integer and a date
|
22
|
+
# respectively, rather than have to deal with them as strings.
|
23
|
+
module Typecaster
|
24
|
+
def self.included(klass) #:nodoc:
|
25
|
+
klass.extend Typecaster::ClassMethods
|
26
|
+
klass.class_eval{ include Typecaster::InstanceMethods }
|
27
|
+
klass.alias_method_chain :initialize, :typecasting
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
# Accepts a set of attribute-name/lambda pairs which are used
|
32
|
+
# to typecast string values injected through the constructor.
|
33
|
+
# Typically needed when populating an +AttributesContainer+
|
34
|
+
# directly from request params. Typecasting kicks in for
|
35
|
+
# a given value _only_ if it is a string.
|
36
|
+
#
|
37
|
+
# Typecast information is inherited by subclasses; however be
|
38
|
+
# aware that explicitly invoking +typecast+ in a subclass will
|
39
|
+
# discard inherited typecast information leaving only the casts
|
40
|
+
# defined in the subclass.
|
41
|
+
#
|
42
|
+
# Common typecasts such as integer, float, datetime etc. are
|
43
|
+
# available through predefined helpers. See TypecastHelpers
|
44
|
+
# for a full list.
|
45
|
+
#
|
46
|
+
# Example:
|
47
|
+
#
|
48
|
+
# class Demon
|
49
|
+
# include Wrest::Components::AttributesContainer
|
50
|
+
# include Wrest::Components::AttributesContainer::Typecaster
|
51
|
+
#
|
52
|
+
# typecast :age => as_integer,
|
53
|
+
# :chi => lambda{|chi| Chi.new(chi)}
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# kai_wren = Demon.new('age' => '1500', 'chi' => '1024')
|
57
|
+
# kai_wren.age # => 1500
|
58
|
+
# kai_wren.chi # => #<Chi:0x113af8c @count="1024">
|
59
|
+
def typecast(cast_map)
|
60
|
+
@typecast_map = @typecast_map ? @typecast_map.merge(cast_map.symbolize_keys) : cast_map.symbolize_keys
|
61
|
+
end
|
62
|
+
|
63
|
+
def typecast_map #:nodoc:
|
64
|
+
if defined?(@typecast_map)
|
65
|
+
@typecast_map
|
66
|
+
elsif superclass != Object && superclass.respond_to?(:typecast_map)
|
67
|
+
superclass.typecast_map
|
68
|
+
else
|
69
|
+
{}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def as_base64Binary
|
74
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['base64Binary']
|
75
|
+
end
|
76
|
+
|
77
|
+
def as_boolean
|
78
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['boolean']
|
79
|
+
end
|
80
|
+
|
81
|
+
def as_decimal
|
82
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['decimal']
|
83
|
+
end
|
84
|
+
|
85
|
+
def as_date
|
86
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['date']
|
87
|
+
end
|
88
|
+
|
89
|
+
def as_datetime
|
90
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['datetime']
|
91
|
+
end
|
92
|
+
|
93
|
+
def as_float
|
94
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['float']
|
95
|
+
end
|
96
|
+
|
97
|
+
def as_integer
|
98
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['integer']
|
99
|
+
end
|
100
|
+
|
101
|
+
def as_symbol
|
102
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['symbol']
|
103
|
+
end
|
104
|
+
|
105
|
+
def as_yaml
|
106
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['yaml']
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
module InstanceMethods # :nodoc:
|
111
|
+
def initialize_with_typecasting(attributes = {}) # :nodoc:
|
112
|
+
initialize_without_typecasting(attributes)
|
113
|
+
self.class.typecast_map.each do |key, typecaster|
|
114
|
+
value = @attributes[key]
|
115
|
+
@attributes[key] = typecaster.call(value) if value.is_a?(String)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -7,16 +7,33 @@
|
|
7
7
|
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
8
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
9
|
|
10
|
-
module Wrest
|
10
|
+
module Wrest
|
11
11
|
module Components
|
12
12
|
# A mutator understands how to transform
|
13
13
|
# one tuple(key/value pair) from a hash
|
14
14
|
# into another
|
15
15
|
module Mutators
|
16
|
+
# All sublasses of Mutators::Base are automatically
|
17
|
+
# registered here by underscored, symbolised class name.
|
18
|
+
REGISTRY = {}
|
19
|
+
|
20
|
+
# Makes referencing and chaining mutators easy.
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
# Mutators.chain(:xml_mini_type_caster, :camel_to_snake_case)
|
24
|
+
# is equivalent to
|
25
|
+
# Wrest::Components::Mutators::XmlMiniTypeCaster.new(Wrest::Components::Mutators::CamelToSnakeCase.new)
|
26
|
+
def self.chain(*mutator_keys)
|
27
|
+
mutator_key = mutator_keys.pop
|
28
|
+
mutator_keys.reverse.inject(REGISTRY[mutator_key].new) do |next_instance, next_key|
|
29
|
+
REGISTRY[next_key].new(next_instance)
|
30
|
+
end
|
31
|
+
end
|
16
32
|
end
|
17
33
|
end
|
18
34
|
end
|
19
35
|
|
20
36
|
require "#{WREST_ROOT}/wrest/components/mutators/base"
|
21
37
|
require "#{WREST_ROOT}/wrest/components/mutators/xml_simple_type_caster"
|
38
|
+
require "#{WREST_ROOT}/wrest/components/mutators/xml_mini_type_caster"
|
22
39
|
require "#{WREST_ROOT}/wrest/components/mutators/camel_to_snake_case"
|
@@ -1,43 +1,56 @@
|
|
1
1
|
# Copyright 2009 Sidu Ponnappa
|
2
2
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
7
|
-
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
|
-
# See the License for the specific language governing permissions and limitations under the License.
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
7
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
10
|
+
module Wrest
|
11
|
+
module Components
|
12
|
+
# This is a base implementation of a
|
13
|
+
# hash mutator that ensures that the <tt>mutate</tt> method
|
14
|
+
# will chain to the next mutator by using a
|
15
|
+
# template method.
|
16
|
+
class Mutators::Base
|
17
|
+
attr_reader :next_mutator
|
18
|
+
|
19
|
+
# Registers all subclasses of Mutators::Base in
|
20
|
+
# Mutators::REGISTRY making it easy to reference
|
21
|
+
# and chain them later.
|
22
|
+
#
|
23
|
+
# See Mutators#chain for more information.
|
24
|
+
def self.inherited(subklass)
|
25
|
+
Wrest::Components::Mutators::REGISTRY[subklass.name.demodulize.underscore.to_sym] = subklass unless subklass.name.blank?
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(next_mutator = nil)
|
29
|
+
@next_mutator = next_mutator
|
30
|
+
end
|
31
|
+
|
32
|
+
# This is a template method which operates on a tuple (well, pair)
|
33
|
+
# from a hash map and guarantees mutator chaining.
|
34
|
+
#
|
35
|
+
# Iterating over any hash using <tt>each</tt> injects
|
36
|
+
# each key/value pair from the hash in the
|
37
|
+
# form of an array.
|
38
|
+
# This method expects of this form as an argument, i.e.
|
39
|
+
# an array with the structure [:key, :value]
|
40
|
+
#
|
41
|
+
# The implementation of the mutation is achieved by
|
42
|
+
# overriding the <tt>do_mutate</tt> method in a subclass.
|
43
|
+
# Note that failing to do so will result in an exception
|
44
|
+
# at runtime.
|
45
|
+
def mutate(tuple)
|
46
|
+
out_tuple = do_mutate(tuple)
|
47
|
+
next_mutator ? next_mutator.mutate(out_tuple) : out_tuple
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
def do_mutate(tuple)
|
52
|
+
raise Wrest::Exceptions::MethodNotOverriddenException
|
53
|
+
end
|
54
|
+
end
|
42
55
|
end
|
43
|
-
end
|
56
|
+
end
|
@@ -7,14 +7,16 @@
|
|
7
7
|
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
8
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
9
|
|
10
|
-
module Wrest
|
11
|
-
|
10
|
+
module Wrest
|
11
|
+
module Components
|
12
12
|
# Converts the key to snake case
|
13
13
|
#
|
14
14
|
# Example:
|
15
|
-
# Mutators::CamelToSnakeCase.new.mutate(['Spirit-Sword', 'true']) # => ['spirit_sword', 'true']
|
16
|
-
|
17
|
-
|
15
|
+
# Mutators::CamelToSnakeCase.new.mutate(['Spirit-Sword', 'true']) # => ['spirit_sword', 'true']**
|
16
|
+
class Mutators::CamelToSnakeCase < Mutators::Base
|
17
|
+
def do_mutate(tuple)
|
18
|
+
[tuple.first.underscore, tuple.last]
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright 2009 Sidu Ponnappa
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
7
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
9
|
+
|
10
|
+
|
11
|
+
module Wrest
|
12
|
+
module Components
|
13
|
+
# This mutator undertands how do type casting
|
14
|
+
# using the type data embedded in a hash
|
15
|
+
# created by deserialising an xml using
|
16
|
+
# ActiveSupport::XmlMini
|
17
|
+
class Mutators::XmlMiniTypeCaster < Mutators::Base
|
18
|
+
def do_mutate(tuple)
|
19
|
+
out_key, in_value = tuple
|
20
|
+
|
21
|
+
case in_value
|
22
|
+
when Hash
|
23
|
+
if in_value['nil'] == 'true'
|
24
|
+
out_value = nil
|
25
|
+
elsif in_value.key?('type')
|
26
|
+
caster = ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING[in_value['type']]
|
27
|
+
out_value = caster ? caster.call(in_value['__content__']) : in_value
|
28
|
+
elsif in_value.key?('__content__')
|
29
|
+
out_value = in_value['__content__']
|
30
|
+
else
|
31
|
+
out_value = in_value.mutate_using(self)
|
32
|
+
end
|
33
|
+
when Array
|
34
|
+
out_value = in_value.collect{|hash| hash.mutate_using(self)}
|
35
|
+
else
|
36
|
+
out_value = in_value
|
37
|
+
end
|
38
|
+
|
39
|
+
[out_key, out_value]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -7,29 +7,31 @@
|
|
7
7
|
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
8
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
module Wrest
|
11
|
+
module Components
|
12
|
+
# This mutator undertands how do type casting
|
13
|
+
# using the type data embedded in a hash
|
14
|
+
# created by deserialising an xml using
|
15
|
+
# xml-simple
|
16
|
+
class Mutators::XmlSimpleTypeCaster < Mutators::Base
|
17
|
+
def do_mutate(tuple)
|
18
|
+
out_key = tuple.first
|
19
|
+
in_value = tuple.last[0]
|
20
|
+
out_value = in_value
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
case in_value
|
23
|
+
when Hash
|
24
|
+
if in_value['nil'] == 'true'
|
25
|
+
out_value = nil
|
26
|
+
elsif in_value.key?('type')
|
27
|
+
out_value = ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING[in_value['type']].call(in_value['content'])
|
28
|
+
else
|
29
|
+
out_value = in_value.mutate_using(self)
|
30
|
+
end
|
29
31
|
end
|
30
|
-
end
|
31
32
|
|
32
|
-
|
33
|
+
[out_key, out_value]
|
34
|
+
end
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -1,25 +1,28 @@
|
|
1
1
|
# Copyright 2009 Sidu Ponnappa
|
2
2
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
7
|
-
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
|
-
# See the License for the specific language governing permissions and limitations under the License.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License
|
7
|
+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
|
+
# See the License for the specific language governing permissions and limitations under the License.
|
9
|
+
|
10
|
+
|
11
|
+
module Wrest
|
12
|
+
module Components
|
13
|
+
# Contains strategies/lambdas which know how to deserialise
|
14
|
+
# different content types.
|
15
|
+
module Translators
|
16
|
+
# Loads the appropriate desirialisation strategy based on
|
17
|
+
# the content type
|
18
|
+
def self.lookup(content_type)
|
19
|
+
translator = CONTENT_TYPES[content_type]
|
20
|
+
translator || (raise Wrest::Exceptions::UnsupportedContentTypeException.new("Unsupported content type #{content_type}"))
|
21
|
+
end
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
26
|
require "#{WREST_ROOT}/wrest/components/translators/xml"
|
24
27
|
require "#{WREST_ROOT}/wrest/components/translators/json"
|
25
|
-
require "#{WREST_ROOT}/wrest/components/translators/content_types"
|
28
|
+
require "#{WREST_ROOT}/wrest/components/translators/content_types"
|
@@ -7,8 +7,8 @@
|
|
7
7
|
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
8
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
9
|
|
10
|
-
module Wrest
|
11
|
-
module Translators
|
10
|
+
module Wrest
|
11
|
+
module Components::Translators
|
12
12
|
# Maps content types to deserialisers
|
13
13
|
CONTENT_TYPES = {
|
14
14
|
'application/xml' => Wrest::Components::Translators::Xml,
|
@@ -7,16 +7,19 @@
|
|
7
7
|
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
8
8
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
9
|
|
10
|
-
module Wrest::Components::Translators
|
11
|
-
module Json
|
12
|
-
extend self
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
module Wrest
|
12
|
+
module Components
|
13
|
+
module Translators::Json
|
14
|
+
extend self
|
15
|
+
|
16
|
+
def deserialise(response)
|
17
|
+
ActiveSupport::JSON.decode(response.body)
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
def serialise(hash)
|
21
|
+
ActiveSupport::JSON.encode(hash)
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|