restfulie 0.7.2 → 0.8.0
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/Gemfile +21 -0
- data/README.textile +10 -9
- data/Rakefile +12 -5
- data/lib/restfulie/client/base.rb +10 -6
- data/lib/restfulie/client/http/adapter.rb +48 -33
- data/lib/restfulie/client/http/atom_ext.rb +3 -68
- data/lib/restfulie/client/http/core_ext/http.rb +19 -0
- data/lib/restfulie/client/http/core_ext.rb +6 -0
- data/lib/restfulie/client/http/error.rb +3 -6
- data/lib/restfulie/client/http/marshal.rb +35 -49
- data/lib/restfulie/client/http/xml_ext.rb +7 -0
- data/lib/restfulie/client/http.rb +2 -2
- data/lib/restfulie/client/mikyung/concatenator.rb +15 -0
- data/lib/restfulie/client/mikyung/core.rb +44 -0
- data/lib/restfulie/client/mikyung/languages.rb +29 -0
- data/lib/restfulie/client/mikyung/rest_process_model.rb +114 -0
- data/lib/restfulie/client/mikyung/steady_state_walker.rb +32 -0
- data/lib/restfulie/client/mikyung/then_condition.rb +33 -0
- data/lib/restfulie/client/mikyung/when_condition.rb +53 -0
- data/lib/restfulie/client/mikyung.rb +19 -0
- data/lib/restfulie/client.rb +1 -0
- data/lib/restfulie/common/converter/atom/builder.rb +109 -0
- data/lib/restfulie/common/converter/atom/helpers.rb +9 -0
- data/lib/restfulie/common/converter/atom.rb +87 -0
- data/lib/restfulie/common/converter/values.rb +29 -0
- data/lib/restfulie/common/converter.rb +11 -0
- data/lib/restfulie/common/core_ext/proc.rb +48 -0
- data/lib/restfulie/common/core_ext.rb +5 -0
- data/lib/restfulie/common/errors.rb +6 -0
- data/lib/restfulie/common/representation/atom/atom.rng +597 -0
- data/lib/restfulie/common/representation/atom/base.rb +375 -0
- data/lib/restfulie/common/representation/atom/entry.rb +107 -0
- data/lib/restfulie/common/representation/atom/feed.rb +106 -0
- data/lib/restfulie/common/representation/atom.rb +43 -33
- data/lib/restfulie/common/representation/json.rb +1 -2
- data/lib/restfulie/common/representation/xml.rb +209 -23
- data/lib/restfulie/common/representation.rb +0 -1
- data/lib/restfulie/common.rb +2 -3
- data/lib/restfulie/server/action_controller/base.rb +21 -2
- data/lib/restfulie/server/action_controller/params_parser.rb +16 -16
- data/lib/restfulie/server/action_controller/restful_responder.rb +3 -3
- data/lib/restfulie/server/action_controller/routing/patch.rb +6 -0
- data/lib/restfulie/server/action_view/helpers.rb +8 -8
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +3 -2
- data/lib/restfulie/server/core_ext/array.rb +13 -12
- metadata +51 -34
- data/lib/restfulie/client/http/link.rb +0 -39
- data/lib/restfulie/client/http/xml.rb +0 -4
- data/lib/restfulie/common/builder/builder_base.rb +0 -73
- data/lib/restfulie/common/builder/helpers.rb +0 -22
- data/lib/restfulie/common/builder/marshalling/atom.rb +0 -197
- data/lib/restfulie/common/builder/marshalling/base.rb +0 -12
- data/lib/restfulie/common/builder/marshalling/json.rb +0 -2
- data/lib/restfulie/common/builder/marshalling/xml.rb +0 -183
- data/lib/restfulie/common/builder/marshalling.rb +0 -16
- data/lib/restfulie/common/builder/rules/collection_rule.rb +0 -10
- data/lib/restfulie/common/builder/rules/custom_attributes.rb +0 -24
- data/lib/restfulie/common/builder/rules/link.rb +0 -20
- data/lib/restfulie/common/builder/rules/links.rb +0 -9
- data/lib/restfulie/common/builder/rules/member_rule.rb +0 -8
- data/lib/restfulie/common/builder/rules/namespace.rb +0 -35
- data/lib/restfulie/common/builder/rules/rules_base.rb +0 -77
- data/lib/restfulie/common/builder.rb +0 -17
- data/lib/vendor/atom/configuration.rb +0 -24
- data/lib/vendor/atom/pub.rb +0 -250
- data/lib/vendor/atom/xml/parser.rb +0 -373
- data/lib/vendor/atom.rb +0 -771
@@ -0,0 +1,15 @@
|
|
1
|
+
# Concatenates pure text in order to build messages
|
2
|
+
# that are used as patterns.
|
3
|
+
# Usage:
|
4
|
+
# When there is a machine
|
5
|
+
#
|
6
|
+
# Will invoke concatenate 'machine' with 'a' with 'is' with 'there'
|
7
|
+
class Restfulie::Client::Mikyung::Concatenator
|
8
|
+
attr_reader :content
|
9
|
+
def initialize(content, *args)
|
10
|
+
@content = content
|
11
|
+
args.each do |arg|
|
12
|
+
@content << " " << arg.content
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# iterates following a series of steps provided a goal and a starting uri.
|
2
|
+
#
|
3
|
+
# Restfulie::Client::Mikyung.achieve(objective).at(uri).run
|
4
|
+
#
|
5
|
+
# In order to implement your own walker, supply an object that respond to the move method.
|
6
|
+
# Check the run method code.
|
7
|
+
class Restfulie::Client::Mikyung::Core
|
8
|
+
|
9
|
+
attr_reader :start, :goal, :walker
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@walker = Restfulie::Client::Mikyung::SteadyStateWalker.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def walks_with(walker)
|
16
|
+
@walker = walker
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
# initializes with a goal in mind
|
21
|
+
def achieve(goal)
|
22
|
+
@goal = goal
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def at(start)
|
27
|
+
@start = start
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
# keeps changing from a steady state to another until its goal has been achieved
|
32
|
+
def run
|
33
|
+
@start = current = (@start.kind_of? String) ? Restfulie.at(@start).get : @start
|
34
|
+
|
35
|
+
while(!@goal.completed?(current))
|
36
|
+
current = @walker.move(@goal, current, self)
|
37
|
+
end
|
38
|
+
current
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
class Restfulie::Client::UnableToAchieveGoalError < Restfulie::Common::Error::RestfulieError
|
44
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Restfulie::Client::Mikyung::German
|
2
|
+
def Wenn(concat, &block)
|
3
|
+
When(concat, &block)
|
4
|
+
end
|
5
|
+
def Und(concat, &block)
|
6
|
+
And(concat, &block)
|
7
|
+
end
|
8
|
+
def Aber(concat, &block)
|
9
|
+
But(concat, &block)
|
10
|
+
end
|
11
|
+
def Dann(concat, &block)
|
12
|
+
Then(concat, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Restfulie::Client::Mikyung::Portuguese
|
17
|
+
def Quando(concat, &block)
|
18
|
+
When(concat, &block)
|
19
|
+
end
|
20
|
+
def E(concat, &block)
|
21
|
+
And(concat, &block)
|
22
|
+
end
|
23
|
+
def Mas(concat, &block)
|
24
|
+
But(concat, &block)
|
25
|
+
end
|
26
|
+
def Entao(concat, &block)
|
27
|
+
Then(concat, &block)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# a configuration error
|
2
|
+
class Restfulie::Client::Mikyung::ConfigurationError < Restfulie::Common::Error::RestfulieError
|
3
|
+
end
|
4
|
+
|
5
|
+
# Provides a DSL to build your process in a human readable way.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# When there is a machine
|
9
|
+
# And already installed
|
10
|
+
# Then reboot
|
11
|
+
#
|
12
|
+
# Before creating your DSL you should provide your method content:
|
13
|
+
#
|
14
|
+
# When /there (are|is an|is a|is) (.*)/ do |resource, regex|
|
15
|
+
# resource.keys.first==regex[2]
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# When "already installed" do |resource|
|
19
|
+
# @installed
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Then "reboot" do |resource|
|
23
|
+
# resource.machine.boot.post! :boot => {:reason => "Installed #{@software[:name]}"}
|
24
|
+
# end
|
25
|
+
class Restfulie::Client::Mikyung::RestProcessModel
|
26
|
+
|
27
|
+
# concatenates anything to a current expression
|
28
|
+
def method_missing(sym, *args)
|
29
|
+
Restfulie::Client::Mikyung::Concatenator.new(sym.to_s, *args)
|
30
|
+
end
|
31
|
+
|
32
|
+
# the list of results
|
33
|
+
def then_rules
|
34
|
+
@then_rules ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
# the list of conditions
|
38
|
+
def conditions
|
39
|
+
@conditions ||= []
|
40
|
+
end
|
41
|
+
|
42
|
+
# the list of conditional rules
|
43
|
+
def when_rules
|
44
|
+
@when_rules ||= []
|
45
|
+
end
|
46
|
+
|
47
|
+
# creates a When rule or block
|
48
|
+
#
|
49
|
+
# When blocks should return true or false whether the current resource matches what you expect:
|
50
|
+
# When /there (are|is an|is a|is) (.*)/ do |resource, regex|
|
51
|
+
# resource.keys.first==regex[2]
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# When rules will group conditions and rules together:
|
55
|
+
# When there is a machine
|
56
|
+
# And already installed
|
57
|
+
# Then reboot
|
58
|
+
def When(concat, &block)
|
59
|
+
if concat.respond_to? :content
|
60
|
+
@condition = when_factory(concat)
|
61
|
+
conditions << @condition
|
62
|
+
else
|
63
|
+
when_rules << [concat, block]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Adds a constraint to the current scenario
|
68
|
+
def And(concat)
|
69
|
+
@condition.and when_factory(concat)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Adds a negative constraint to the current scenario
|
73
|
+
def But(concat)
|
74
|
+
@condition.but when_factory(concat)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates a result rule
|
78
|
+
#
|
79
|
+
# example:
|
80
|
+
# Then "reboot" do |resource|
|
81
|
+
# resource.machine.boot.post! :boot => {:reason => "Installed #{@software[:name]}"}
|
82
|
+
# end
|
83
|
+
def Then(concat, &block)
|
84
|
+
if concat.respond_to? :content
|
85
|
+
@condition.results_on Restfulie::Client::Mikyung::ThenCondition.new(concat.content)
|
86
|
+
else
|
87
|
+
then_rules << [concat, block]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Goes through every scenario and finds which one fits the current server steady state.
|
92
|
+
# Picks this step and executes the business rule attached to it.
|
93
|
+
def next_step(resource, mikyung)
|
94
|
+
conditions.each do |c|
|
95
|
+
if c.should_run_for(resource, self)
|
96
|
+
return c.execute(resource, self, mikyung)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def when_factory(concat)
|
105
|
+
rule = when_rules.find do |rule|
|
106
|
+
concat.content.match(rule[0])
|
107
|
+
end
|
108
|
+
if rule.nil?
|
109
|
+
raise Restfulie::Client::Mikyung::ConfigurationError, "You forgot to create '#{concat.content}' prior to its usage."
|
110
|
+
end
|
111
|
+
Restfulie::Client::Mikyung::WhenCondition.new(concat.content, rule, concat.content.match(rule[0]))
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# A steady walker that tries 3 times each step
|
2
|
+
class Restfulie::Client::Mikyung::SteadyStateWalker
|
3
|
+
|
4
|
+
def move(goal, current, mikyung)
|
5
|
+
step = goal.next_step(current, mikyung)
|
6
|
+
raise Restfulie::Client::UnableToAchieveGoalError, "No step was found for #{current}" unless step
|
7
|
+
Restfulie::Common::Logger.logger.debug "Mikyung > next step will be #{step}"
|
8
|
+
step = step.new if step.kind_of? Class
|
9
|
+
try_to_execute(step, current, 3, mikyung)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def try_to_execute(step, current, max_attempts, mikyung)
|
15
|
+
raise "Unable to proceed when trying to #{step}" if max_attempts == 0
|
16
|
+
|
17
|
+
resource = step
|
18
|
+
raise "Step returned 'give up'" if resource.nil?
|
19
|
+
|
20
|
+
if step.respond_to?(:execute)
|
21
|
+
resource = step.execute(current, mikyung)
|
22
|
+
end
|
23
|
+
|
24
|
+
if resource.response.code != 200
|
25
|
+
try_to_execute(step, current, max_attempts-1, mikyung)
|
26
|
+
else
|
27
|
+
Restfulie::Common::Logger.logger.debug resource.response.body
|
28
|
+
resource
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# A conclusion to a step.
|
2
|
+
#
|
3
|
+
# Whenever a step rule matches, there are a series of conditions to be executed.
|
4
|
+
class Restfulie::Client::Mikyung::ThenCondition
|
5
|
+
|
6
|
+
attr_reader :description
|
7
|
+
|
8
|
+
# creates a new result, based on this description
|
9
|
+
def initialize(description)
|
10
|
+
@description = description
|
11
|
+
end
|
12
|
+
|
13
|
+
# finds the rule for this result and executes it
|
14
|
+
def execute(resource, goal, mikyung)
|
15
|
+
goal.then_rules.each do |rule|
|
16
|
+
if (matches = Regexp.new(rule[0]).match(@description))
|
17
|
+
return invoke_rule(rule[1], resource, matches, mikyung)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def invoke_rule(rule, resource, matches, mikyung)
|
25
|
+
if rule.arity==1
|
26
|
+
rule.call(resource)
|
27
|
+
elsif rule.arity==2
|
28
|
+
rule.call(resource, matches)
|
29
|
+
else
|
30
|
+
rule.call(resource, matches, mikyung)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Checks whether one or more rule holds and is capable of executing results.
|
2
|
+
class Restfulie::Client::Mikyung::WhenCondition
|
3
|
+
|
4
|
+
# Creates a conditional execution based on a description.
|
5
|
+
# Its rule is an array where its first element represents a rule name and second a lambda that returns true or false
|
6
|
+
# Its params are extra params that might be passed to the rule
|
7
|
+
# Example
|
8
|
+
# WhenCondition.new("when running", ["", lambda { |resource| resource.human.state=='running' }], "")
|
9
|
+
def initialize(description, rule, params)
|
10
|
+
@description = description
|
11
|
+
@results = []
|
12
|
+
@extra = []
|
13
|
+
@rule = rule
|
14
|
+
@params = params
|
15
|
+
end
|
16
|
+
|
17
|
+
# will execute the first attached result
|
18
|
+
def execute(resource, goal, mikyung)
|
19
|
+
@results.each do |result|
|
20
|
+
Restfulie::Common::Logger.logger.info("will '#{result.description}'")
|
21
|
+
return result.execute(resource, goal, mikyung)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# checks whether this step should execute for a specific resource
|
26
|
+
def should_run_for(resource, goal)
|
27
|
+
if @rule[1].arity==2
|
28
|
+
rule_accepts = @rule[1].call(resource, @params)
|
29
|
+
else
|
30
|
+
rule_accepts = @rule[1].call(resource)
|
31
|
+
end
|
32
|
+
return false unless rule_accepts
|
33
|
+
!@extra.find do |condition|
|
34
|
+
!condition.should_run_for(resource, goal)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# adds an extra condition to this step
|
39
|
+
def and(condition)
|
40
|
+
@extra << condition
|
41
|
+
end
|
42
|
+
|
43
|
+
# adds an extra condition to this step
|
44
|
+
def but(condition)
|
45
|
+
@extra << condition
|
46
|
+
end
|
47
|
+
|
48
|
+
# adds an extra result to this step
|
49
|
+
def results_on(result)
|
50
|
+
@results << result
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Restfulie::Client::Mikyung
|
2
|
+
end
|
3
|
+
|
4
|
+
%w(
|
5
|
+
when_condition
|
6
|
+
then_condition
|
7
|
+
rest_process_model
|
8
|
+
concatenator
|
9
|
+
core
|
10
|
+
steady_state_walker
|
11
|
+
languages
|
12
|
+
).each do |file|
|
13
|
+
require "restfulie/client/mikyung/#{file}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Restfulie::Mikyung entry point is based on its core
|
17
|
+
# implementation.
|
18
|
+
class Restfulie::Mikyung < Restfulie::Client::Mikyung::Core
|
19
|
+
end
|
data/lib/restfulie/client.rb
CHANGED
@@ -0,0 +1,109 @@
|
|
1
|
+
module Restfulie::Common::Converter::Atom
|
2
|
+
class Builder
|
3
|
+
attr_accessor :atom_type
|
4
|
+
|
5
|
+
def initialize(atom_type, obj)
|
6
|
+
@doc = Nokogiri::XML::Document.new
|
7
|
+
@obj = obj
|
8
|
+
@parent = @doc.create_element(atom_type.to_s)
|
9
|
+
@parent.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
|
10
|
+
@parent.parent = @doc
|
11
|
+
end
|
12
|
+
|
13
|
+
def values(options = nil, &block)
|
14
|
+
options.each do |key,value|
|
15
|
+
attr = key.to_s
|
16
|
+
if attr =~ /^xmlns(:\w+)?$/
|
17
|
+
ns = attr.split(":", 2)[1]
|
18
|
+
@parent.add_namespace_definition(ns, value)
|
19
|
+
end
|
20
|
+
end if options
|
21
|
+
|
22
|
+
yield Restfulie::Common::Converter::Components::Values.new(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def members(a_collection = nil, &block)
|
26
|
+
collection = a_collection || @obj
|
27
|
+
raise Restfulie::Common::Error::BuilderError("Members method require a collection to execute") unless collection.respond_to?(:each)
|
28
|
+
collection.each do |member|
|
29
|
+
entry = @doc.create_element("entry")
|
30
|
+
entry.parent = @parent
|
31
|
+
@parent = entry
|
32
|
+
block.call(self, member)
|
33
|
+
@parent = entry.parent
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def link(relationship, uri, options = {})
|
38
|
+
options["rel"] = relationship.to_s
|
39
|
+
options["href"] = uri
|
40
|
+
insert_value("link", nil, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def insert_value(name, prefix, *args, &block)
|
44
|
+
node = create_element(name.to_s, prefix, *args)
|
45
|
+
node.parent = @parent
|
46
|
+
|
47
|
+
if block_given?
|
48
|
+
@parent = node
|
49
|
+
block.call
|
50
|
+
@parent = node.parent
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def representation
|
55
|
+
Restfulie::Common::Representation::Atom::Factory.create(@doc)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def create_element(node, prefix, *args)
|
61
|
+
node = @doc.create_element(node) do |n|
|
62
|
+
if prefix
|
63
|
+
if namespace = prefix_valid?(prefix)
|
64
|
+
# Adding namespace prefix
|
65
|
+
n.namespace = namespace
|
66
|
+
namespace = nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
args.each do |arg|
|
71
|
+
case arg
|
72
|
+
# Adding XML attributes
|
73
|
+
when Hash
|
74
|
+
arg.each { |k,v|
|
75
|
+
key = k.to_s
|
76
|
+
if key =~ /^xmlns(:\w+)?$/
|
77
|
+
ns_name = key.split(":", 2)[1]
|
78
|
+
n.add_namespace_definition(ns_name, v)
|
79
|
+
next
|
80
|
+
end
|
81
|
+
n[k.to_s] = v.to_s
|
82
|
+
}
|
83
|
+
# Adding XML node content
|
84
|
+
else
|
85
|
+
arg.kind_of?(Time) || arg.kind_of?(DateTime) ? content = arg.xmlschema : content = arg
|
86
|
+
n.content = content
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def prefix_valid?(prefix)
|
93
|
+
ns = @parent.namespace_definitions.find { |x| x.prefix == prefix.to_s }
|
94
|
+
|
95
|
+
unless ns
|
96
|
+
@parent.ancestors.each do |a|
|
97
|
+
next if a == @doc
|
98
|
+
ns = a.namespace_definitions.find { |x| x.prefix == prefix.to_s }
|
99
|
+
break if ns
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
return ns
|
104
|
+
#TODO: raise ArgumentError, "Namespace #{prefix} has not been defined" if wanted
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Restfulie::Common::Converter::Atom::Helpers
|
2
|
+
def collection(obj, *args, &block)
|
3
|
+
Restfulie::Common::Converter::Atom.to_atom(obj, :atom_type => :feed, &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def member(obj, *args, &block)
|
7
|
+
Restfulie::Common::Converter::Atom.to_atom(obj, :atom_type => :entry, &block)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Restfulie::Common::Converter
|
2
|
+
|
3
|
+
module Atom
|
4
|
+
|
5
|
+
mattr_reader :media_type_name
|
6
|
+
@@media_type_name = 'application/atom+xml'
|
7
|
+
|
8
|
+
mattr_reader :headers
|
9
|
+
@@headers = {
|
10
|
+
:get => { 'Accept' => media_type_name },
|
11
|
+
:post => { 'Content-Type' => media_type_name }
|
12
|
+
}
|
13
|
+
|
14
|
+
mattr_reader :recipes
|
15
|
+
@@recipes = {}
|
16
|
+
|
17
|
+
class << self
|
18
|
+
|
19
|
+
def helper
|
20
|
+
Restfulie::Common::Converter::Atom::Helpers
|
21
|
+
end
|
22
|
+
|
23
|
+
def describe_recipe(recipe_name, options={}, &block)
|
24
|
+
raise 'Undefined recipe' unless block_given?
|
25
|
+
raise 'Undefined recipe_name' unless recipe_name
|
26
|
+
@@recipes[recipe_name] = block
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_atom(obj = nil, options = {}, &block)
|
30
|
+
# just instantiate the string with the atom factory
|
31
|
+
return Restfulie::Common::Representation::Atom::Factory.create(obj) if obj.kind_of?(String)
|
32
|
+
|
33
|
+
if block_given?
|
34
|
+
recipe = block
|
35
|
+
elsif options[:recipe]
|
36
|
+
recipe = @@recipes[options[:recipe]]
|
37
|
+
else
|
38
|
+
return obj if obj.respond_to?(:atom_type) && (obj.atom_type == "feed" || obj.atom_type == "entry")
|
39
|
+
raise Restfulie::Common::Error::ConverterError.new("Recipe required")
|
40
|
+
end
|
41
|
+
|
42
|
+
# execute with the builder if a recipe is set (even if the obj is an atom)
|
43
|
+
options[:atom_type] ||= obj.respond_to?(:each) ? :feed : :entry
|
44
|
+
raise Restfulie::Common::Error::ConverterError.new("Undefined atom type #{options[:atom_type]}") unless [:entry,:feed].include?(options[:atom_type])
|
45
|
+
|
46
|
+
# Create representation and proxy
|
47
|
+
builder = Builder.new(options[:atom_type], obj)
|
48
|
+
|
49
|
+
# Check recipe arity size before calling it
|
50
|
+
recipe.call(*[builder, obj, options][0,recipe.arity])
|
51
|
+
|
52
|
+
builder.representation
|
53
|
+
end
|
54
|
+
|
55
|
+
alias_method :unmarshal, :to_atom
|
56
|
+
|
57
|
+
def to_hash(obj)
|
58
|
+
return obj if obj.kind_of?(Hash)
|
59
|
+
|
60
|
+
xml = nil
|
61
|
+
|
62
|
+
if obj.kind_of?(::String)
|
63
|
+
xml = obj
|
64
|
+
elsif obj.respond_to?(:to_xml)
|
65
|
+
xml = obj.to_xml
|
66
|
+
end
|
67
|
+
|
68
|
+
Hash.from_xml(xml).with_indifferent_access unless xml.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def to_s(obj)
|
73
|
+
return obj if obj.kind_of?(String)
|
74
|
+
if obj.respond_to?(:to_xml)
|
75
|
+
obj.to_xml.to_s
|
76
|
+
else
|
77
|
+
obj.to_s
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def marshal(obj, options = nil)
|
82
|
+
to_atom(obj, options).to_xml
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Restfulie::Common::Converter::Components
|
2
|
+
# This is a Blank Slate class to support the renderization of the values block for Resource Representation Interfaces
|
3
|
+
# Every Media type should implement a Builder with a insert_value method that renders the values block to a specific format
|
4
|
+
class Values
|
5
|
+
attr_accessor :builder
|
6
|
+
|
7
|
+
# BlankSlate
|
8
|
+
instance_methods.each do |m|
|
9
|
+
undef_method m unless m.to_s =~ /\[\]|method_missing|respond_to\?|^__/
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(builder)
|
13
|
+
@builder = builder
|
14
|
+
@current_prefix = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](prefix)
|
18
|
+
@current_prefix = prefix
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(symbol, *args, &block)
|
23
|
+
name = symbol.to_s
|
24
|
+
prefix = @current_prefix
|
25
|
+
@current_prefix = nil
|
26
|
+
@builder.insert_value(name, prefix, *args, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Proc
|
2
|
+
attr_accessor :helpers
|
3
|
+
alias_method :old_call, :call
|
4
|
+
|
5
|
+
def call(*args)
|
6
|
+
@helpers.nil? ? old_call(*args): call_include_helpers(@helpers, *args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def call_include_helpers(helpers, *args)
|
10
|
+
helpers = [helpers] unless helpers.kind_of?(Array)
|
11
|
+
helpers = helpers.map { |helper| Object.new.send(:extend, helper) }
|
12
|
+
block_caller = eval("self", self.binding)
|
13
|
+
|
14
|
+
m = extensible_module(block_caller)
|
15
|
+
m.send(:define_method, :method_missing) do |symbol, *args, &block|
|
16
|
+
mod = helpers.find { |h| h.respond_to?(symbol) }
|
17
|
+
mod.nil? ? super : mod.send(symbol, *args, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
block_caller.extend(m)
|
21
|
+
result = old_call(*args)
|
22
|
+
m.send(:remove_method, :method_missing)
|
23
|
+
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Search for extending the module in ancestors
|
30
|
+
def extensible_module(object)
|
31
|
+
ancestors = object.instance_eval { (class << self; self; end) }.ancestors
|
32
|
+
|
33
|
+
extend_mod = ancestors.find { |ancestor|
|
34
|
+
!ancestor.instance_methods.include?("method_missing") && ancestor.instance_eval { (class << self; self; end) }.ancestors.include?(ProcIncludedHelpers)
|
35
|
+
}
|
36
|
+
|
37
|
+
if extend_mod.nil?
|
38
|
+
extend_mod = Module.new
|
39
|
+
extend_mod.extend(ProcIncludedHelpers)
|
40
|
+
end
|
41
|
+
|
42
|
+
extend_mod
|
43
|
+
end
|
44
|
+
|
45
|
+
module ProcIncludedHelpers; end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
@@ -6,4 +6,10 @@ module Restfulie::Common::Error
|
|
6
6
|
# Atom marshallinh error
|
7
7
|
class AtomMarshallingError < MarshallingError; end
|
8
8
|
class NameSpaceError < AtomMarshallingError; end
|
9
|
+
|
10
|
+
# Converter
|
11
|
+
class ConverterError < RestfulieError; end
|
12
|
+
|
13
|
+
# builder
|
14
|
+
class BuilderError < RestfulieError; end
|
9
15
|
end
|