restfulie 0.8.0 → 0.8.1

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.
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