restfulie 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/Gemfile +10 -5
  2. data/Rakefile +5 -2
  3. data/lib/restfulie.rb +10 -5
  4. data/lib/restfulie/client.rb +13 -9
  5. data/lib/restfulie/client/base.rb +24 -65
  6. data/lib/restfulie/client/configuration.rb +62 -64
  7. data/lib/restfulie/client/entry_point.rb +36 -0
  8. data/lib/restfulie/client/ext/atom_ext.rb +12 -0
  9. data/lib/restfulie/client/ext/http_ext.rb +22 -0
  10. data/lib/restfulie/client/ext/json_ext.rb +12 -0
  11. data/lib/restfulie/client/ext/xml_ext.rb +4 -0
  12. data/lib/restfulie/client/http.rb +25 -13
  13. data/lib/restfulie/client/http/cache.rb +22 -22
  14. data/lib/restfulie/client/http/error.rb +70 -70
  15. data/lib/restfulie/client/http/link_request_builder.rb +15 -0
  16. data/lib/restfulie/client/http/request_adapter.rb +209 -0
  17. data/lib/restfulie/client/http/request_builder.rb +107 -0
  18. data/lib/restfulie/client/http/request_builder_executor.rb +24 -0
  19. data/lib/restfulie/client/http/request_executor.rb +17 -0
  20. data/lib/restfulie/client/http/request_follow.rb +42 -0
  21. data/lib/restfulie/client/http/request_follow_executor.rb +10 -0
  22. data/lib/restfulie/client/http/request_history.rb +69 -0
  23. data/lib/restfulie/client/http/request_history_executor.rb +10 -0
  24. data/lib/restfulie/client/http/request_marshaller.rb +127 -0
  25. data/lib/restfulie/client/http/request_marshaller_executor.rb +10 -0
  26. data/lib/restfulie/client/http/response.rb +23 -0
  27. data/lib/restfulie/client/http/response_handler.rb +67 -0
  28. data/lib/restfulie/client/http/response_holder.rb +9 -0
  29. data/lib/restfulie/client/mikyung.rb +17 -14
  30. data/lib/restfulie/client/mikyung/concatenator.rb +15 -12
  31. data/lib/restfulie/client/mikyung/core.rb +65 -39
  32. data/lib/restfulie/client/mikyung/languages.rb +8 -26
  33. data/lib/restfulie/client/mikyung/languages/german.rb +24 -0
  34. data/lib/restfulie/client/mikyung/languages/portuguese.rb +23 -0
  35. data/lib/restfulie/client/mikyung/rest_process_model.rb +184 -107
  36. data/lib/restfulie/client/mikyung/steady_state_walker.rb +34 -28
  37. data/lib/restfulie/client/mikyung/then_condition.rb +33 -27
  38. data/lib/restfulie/client/mikyung/when_condition.rb +53 -49
  39. data/lib/restfulie/common.rb +7 -12
  40. data/lib/restfulie/common/converter.rb +20 -9
  41. data/lib/restfulie/common/converter/atom.rb +8 -83
  42. data/lib/restfulie/common/converter/atom/base.rb +89 -0
  43. data/lib/restfulie/common/converter/atom/builder.rb +101 -99
  44. data/lib/restfulie/common/converter/atom/helpers.rb +16 -8
  45. data/lib/restfulie/common/converter/json.rb +12 -0
  46. data/lib/restfulie/common/converter/json/base.rb +84 -0
  47. data/lib/restfulie/common/converter/json/builder.rb +102 -0
  48. data/lib/restfulie/common/converter/json/helpers.rb +17 -0
  49. data/lib/restfulie/common/converter/values.rb +30 -26
  50. data/lib/restfulie/common/converter/xml.rb +14 -0
  51. data/lib/restfulie/common/converter/xml/base.rb +61 -0
  52. data/lib/restfulie/common/converter/xml/builder.rb +112 -0
  53. data/lib/restfulie/common/converter/xml/helpers.rb +17 -0
  54. data/lib/restfulie/common/converter/xml/link.rb +25 -0
  55. data/lib/restfulie/common/converter/xml/links.rb +25 -0
  56. data/lib/restfulie/common/core_ext.rb +1 -5
  57. data/lib/restfulie/common/core_ext/hash.rb +12 -0
  58. data/lib/restfulie/common/error.rb +19 -0
  59. data/lib/restfulie/common/logger.rb +17 -9
  60. data/lib/restfulie/common/representation.rb +9 -10
  61. data/lib/restfulie/common/representation/atom.rb +15 -47
  62. data/lib/restfulie/common/representation/atom/base.rb +122 -365
  63. data/lib/restfulie/common/representation/atom/category.rb +41 -0
  64. data/lib/restfulie/common/representation/atom/entry.rb +52 -100
  65. data/lib/restfulie/common/representation/atom/factory.rb +43 -0
  66. data/lib/restfulie/common/representation/atom/feed.rb +103 -99
  67. data/lib/restfulie/common/representation/atom/link.rb +68 -0
  68. data/lib/restfulie/common/representation/atom/person.rb +48 -0
  69. data/lib/restfulie/common/representation/atom/source.rb +59 -0
  70. data/lib/restfulie/common/representation/atom/tag_collection.rb +38 -0
  71. data/lib/restfulie/common/representation/atom/xml.rb +95 -0
  72. data/lib/restfulie/common/representation/generic.rb +30 -29
  73. data/lib/restfulie/common/representation/json.rb +10 -22
  74. data/lib/restfulie/common/representation/json/base.rb +27 -0
  75. data/lib/restfulie/common/representation/json/keys_as_methods.rb +72 -0
  76. data/lib/restfulie/common/representation/json/link.rb +29 -0
  77. data/lib/restfulie/common/representation/json/link_collection.rb +23 -0
  78. data/lib/restfulie/common/representation/xml.rb +18 -227
  79. data/lib/restfulie/server.rb +9 -10
  80. data/lib/restfulie/server/action_controller.rb +10 -12
  81. data/lib/restfulie/server/action_controller/base.rb +18 -15
  82. data/lib/restfulie/server/action_controller/{routing/patch.rb → patch.rb} +0 -0
  83. data/lib/restfulie/server/action_controller/restful_responder.rb +43 -35
  84. data/lib/restfulie/server/action_view.rb +8 -6
  85. data/lib/restfulie/server/action_view/helpers.rb +47 -41
  86. data/lib/restfulie/server/action_view/template_handlers.rb +24 -12
  87. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +17 -12
  88. data/lib/restfulie/server/configuration.rb +22 -19
  89. data/lib/restfulie/server/{restfulie_controller.rb → controller.rb} +1 -10
  90. data/lib/restfulie/server/core_ext.rb +1 -1
  91. data/lib/restfulie/version.rb +14 -0
  92. metadata +52 -16
  93. data/lib/restfulie/client/http/adapter.rb +0 -502
  94. data/lib/restfulie/client/http/atom_ext.rb +0 -4
  95. data/lib/restfulie/client/http/core_ext.rb +0 -6
  96. data/lib/restfulie/client/http/core_ext/http.rb +0 -19
  97. data/lib/restfulie/client/http/marshal.rb +0 -145
  98. data/lib/restfulie/client/http/xml_ext.rb +0 -7
  99. data/lib/restfulie/common/core_ext/proc.rb +0 -48
  100. data/lib/restfulie/common/errors.rb +0 -15
  101. data/lib/restfulie/server/action_controller/routing.rb +0 -12
  102. data/lib/restfulie/server/action_controller/routing/restful_route.rb +0 -14
@@ -1,32 +1,38 @@
1
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?
2
+ module Restfulie
3
+ module Client
4
+ module Mikyung
5
+ class SteadyStateWalker
6
+ def move(goal, current, mikyung)
7
+ step = goal.next_step(current, mikyung)
8
+ raise UnableToAchieveGoalError, "No step was found for #{current}" unless step
9
+ Common::Logger.logger.debug "Mikyung > next step will be #{step}"
10
+ step = step.new if step.kind_of? Class
11
+ try_to_execute(step, current, 3, mikyung)
12
+ end
13
+
14
+ private
15
+
16
+ def try_to_execute(step, current, max_attempts, mikyung)
17
+ raise "Unable to proceed when trying to #{step}" if max_attempts == 0
18
+
19
+ resource = step
20
+ raise "Step returned 'give up'" if resource.nil?
21
+
22
+ if step.respond_to?(:execute)
23
+ resource = step.execute(current, mikyung)
24
+ end
19
25
 
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
26
+ # TODO: should it really retry if it is not 200? Or only if it is on the 50x family?
27
+ # for instance the result could be a 302 redirection
28
+ unless resource.response.code == 200
29
+ try_to_execute(step, current, max_attempts-1, mikyung)
30
+ else
31
+ Common::Logger.logger.debug resource.response.body
32
+ resource
33
+ end
34
+ end
35
+ end
29
36
  end
30
37
  end
31
-
32
- end
38
+ end
@@ -1,33 +1,39 @@
1
1
  # A conclusion to a step.
2
2
  #
3
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)
4
+ module Restfulie
5
+ module Client
6
+ module Mikyung
7
+ class ThenCondition
8
+ attr_reader :description
9
+
10
+ # creates a new result, based on this description
11
+ def initialize(description)
12
+ @description = description
13
+ end
14
+
15
+ # finds the rule for this result and executes it
16
+ def execute(resource, goal, mikyung)
17
+ goal.then_rules.each do |rule|
18
+ if (matches = Regexp.new(rule[0]).match(@description))
19
+ return invoke_rule(rule[1], resource, matches, mikyung)
20
+ end
21
+ end
22
+ nil
23
+ end
24
+
25
+ private
26
+ def invoke_rule(rule, resource, matches, mikyung)
27
+ case rule.arity
28
+ when 1
29
+ rule.call(resource)
30
+ when 2
31
+ rule.call(resource, matches)
32
+ else
33
+ rule.call(resource, matches, mikyung)
34
+ end
35
+ end
18
36
  end
19
37
  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
38
  end
33
- end
39
+ end
@@ -1,53 +1,57 @@
1
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)
2
+ module Restfulie
3
+ module Client
4
+ module Mikyung
5
+ # Creates a conditional execution based on a description.
6
+ # Its rule is an array where its first element represents a rule name and second a lambda that returns true or false
7
+ # Its params are extra params that might be passed to the rule
8
+ # Example
9
+ # WhenCondition.new("when running", ["", lambda { |resource| resource.human.state=='running' }], "")
10
+ class WhenCondition
11
+ def initialize(description, rule, params)
12
+ @description = description
13
+ @results = []
14
+ @extra = []
15
+ @rule = rule
16
+ @params = params
17
+ end
18
+
19
+ # will execute the first attached result
20
+ def execute(resource, goal, mikyung)
21
+ @results.each do |result|
22
+ Restfulie::Common::Logger.logger.info("will '#{result.description}'")
23
+ return result.execute(resource, goal, mikyung)
24
+ end
25
+ end
26
+
27
+ # checks whether this step should execute for a specific resource
28
+ def should_run_for(resource, goal)
29
+ if @rule[1].arity == 2
30
+ rule_accepts = @rule[1].call(resource, @params)
31
+ else
32
+ rule_accepts = @rule[1].call(resource)
33
+ end
34
+ return false unless rule_accepts
35
+ !@extra.find do |condition|
36
+ !condition.should_run_for(resource, goal)
37
+ end
38
+ end
39
+
40
+ # adds an extra condition to this step
41
+ def and(condition)
42
+ @extra << condition
43
+ end
44
+
45
+ # adds an extra condition to this step
46
+ def but(condition)
47
+ @extra << condition
48
+ end
49
+
50
+ # adds an extra result to this step
51
+ def results_on(result)
52
+ @results << result
53
+ end
54
+ end
35
55
  end
36
56
  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
57
  end
@@ -4,19 +4,14 @@ require 'uri'
4
4
  require 'rubygems'
5
5
  require 'active_support'
6
6
  require 'action_controller'
7
+ require 'restfulie/common/core_ext'
7
8
 
8
9
  module Restfulie
9
- module Common; end
10
+ module Common
11
+ autoload :Error, 'restfulie/common/error'
12
+ autoload :Logger, 'restfulie/common/logger'
13
+ autoload :Representation, 'restfulie/common/representation'
14
+ autoload :Converter, 'restfulie/common/converter'
15
+ end
10
16
  end
11
17
 
12
- %w(
13
- errors
14
- logger
15
- core_ext
16
- representation
17
- converter
18
- ).each do |file|
19
- require "restfulie/common/#{file}"
20
- end
21
-
22
- include ActiveSupport::CoreExtensions::Hash
@@ -1,11 +1,22 @@
1
- #initialize namespace
2
- module Restfulie::Common::Converter; end
1
+ module Restfulie
2
+ module Common
3
+ module Converter
4
+ autoload :Values, 'restfulie/common/converter/values'
5
+ autoload :Atom, 'restfulie/common/converter/atom'
6
+ autoload :Json, 'restfulie/common/converter/json'
7
+ autoload :Xml, 'restfulie/common/converter/xml'
3
8
 
4
- %w(
5
- values
6
- atom
7
- atom/builder
8
- atom/helpers
9
- ).each do |file|
10
- require File.join(File.dirname(__FILE__), 'converter', file)
9
+ # Returns the default root element name for an item or collection
10
+ def self.root_element_for(obj)
11
+ if obj.kind_of?(Hash) && obj.size==1
12
+ obj.keys.first.to_s
13
+ elsif obj.kind_of?(Array) && !obj.empty?
14
+ root_element_for(obj.first).to_s.underscore.pluralize
15
+ else
16
+ obj.class.to_s.underscore
17
+ end
18
+ end
19
+ end
20
+ end
11
21
  end
22
+
@@ -1,87 +1,12 @@
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
1
+ module Restfulie
2
+ module Common
3
+ module Converter
4
+ module Atom
5
+ autoload :Base, 'restfulie/common/converter/atom/base'
6
+ autoload :Builder, 'restfulie/common/converter/atom/builder'
7
+ autoload :Helpers, 'restfulie/common/converter/atom/helpers'
8
+ extend Base::ClassMethods
21
9
  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
10
  end
86
11
  end
87
12
  end
@@ -0,0 +1,89 @@
1
+ module Restfulie
2
+ module Common
3
+ module Converter
4
+ module Atom
5
+ module Base
6
+ module ClassMethods
7
+ mattr_reader :media_type_name
8
+ @@media_type_name = 'application/atom+xml'
9
+
10
+ mattr_reader :headers
11
+ @@headers = {
12
+ :get => { 'Accept' => media_type_name },
13
+ :post => { 'Content-Type' => media_type_name }
14
+ }
15
+
16
+ mattr_reader :recipes
17
+ @@recipes = {}
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
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end