restfulie 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/Gemfile +21 -0
  2. data/README.textile +10 -9
  3. data/Rakefile +12 -5
  4. data/lib/restfulie/client/base.rb +10 -6
  5. data/lib/restfulie/client/http/adapter.rb +48 -33
  6. data/lib/restfulie/client/http/atom_ext.rb +3 -68
  7. data/lib/restfulie/client/http/core_ext/http.rb +19 -0
  8. data/lib/restfulie/client/http/core_ext.rb +6 -0
  9. data/lib/restfulie/client/http/error.rb +3 -6
  10. data/lib/restfulie/client/http/marshal.rb +35 -49
  11. data/lib/restfulie/client/http/xml_ext.rb +7 -0
  12. data/lib/restfulie/client/http.rb +2 -2
  13. data/lib/restfulie/client/mikyung/concatenator.rb +15 -0
  14. data/lib/restfulie/client/mikyung/core.rb +44 -0
  15. data/lib/restfulie/client/mikyung/languages.rb +29 -0
  16. data/lib/restfulie/client/mikyung/rest_process_model.rb +114 -0
  17. data/lib/restfulie/client/mikyung/steady_state_walker.rb +32 -0
  18. data/lib/restfulie/client/mikyung/then_condition.rb +33 -0
  19. data/lib/restfulie/client/mikyung/when_condition.rb +53 -0
  20. data/lib/restfulie/client/mikyung.rb +19 -0
  21. data/lib/restfulie/client.rb +1 -0
  22. data/lib/restfulie/common/converter/atom/builder.rb +109 -0
  23. data/lib/restfulie/common/converter/atom/helpers.rb +9 -0
  24. data/lib/restfulie/common/converter/atom.rb +87 -0
  25. data/lib/restfulie/common/converter/values.rb +29 -0
  26. data/lib/restfulie/common/converter.rb +11 -0
  27. data/lib/restfulie/common/core_ext/proc.rb +48 -0
  28. data/lib/restfulie/common/core_ext.rb +5 -0
  29. data/lib/restfulie/common/errors.rb +6 -0
  30. data/lib/restfulie/common/representation/atom/atom.rng +597 -0
  31. data/lib/restfulie/common/representation/atom/base.rb +375 -0
  32. data/lib/restfulie/common/representation/atom/entry.rb +107 -0
  33. data/lib/restfulie/common/representation/atom/feed.rb +106 -0
  34. data/lib/restfulie/common/representation/atom.rb +43 -33
  35. data/lib/restfulie/common/representation/json.rb +1 -2
  36. data/lib/restfulie/common/representation/xml.rb +209 -23
  37. data/lib/restfulie/common/representation.rb +0 -1
  38. data/lib/restfulie/common.rb +2 -3
  39. data/lib/restfulie/server/action_controller/base.rb +21 -2
  40. data/lib/restfulie/server/action_controller/params_parser.rb +16 -16
  41. data/lib/restfulie/server/action_controller/restful_responder.rb +3 -3
  42. data/lib/restfulie/server/action_controller/routing/patch.rb +6 -0
  43. data/lib/restfulie/server/action_view/helpers.rb +8 -8
  44. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +3 -2
  45. data/lib/restfulie/server/core_ext/array.rb +13 -12
  46. metadata +51 -34
  47. data/lib/restfulie/client/http/link.rb +0 -39
  48. data/lib/restfulie/client/http/xml.rb +0 -4
  49. data/lib/restfulie/common/builder/builder_base.rb +0 -73
  50. data/lib/restfulie/common/builder/helpers.rb +0 -22
  51. data/lib/restfulie/common/builder/marshalling/atom.rb +0 -197
  52. data/lib/restfulie/common/builder/marshalling/base.rb +0 -12
  53. data/lib/restfulie/common/builder/marshalling/json.rb +0 -2
  54. data/lib/restfulie/common/builder/marshalling/xml.rb +0 -183
  55. data/lib/restfulie/common/builder/marshalling.rb +0 -16
  56. data/lib/restfulie/common/builder/rules/collection_rule.rb +0 -10
  57. data/lib/restfulie/common/builder/rules/custom_attributes.rb +0 -24
  58. data/lib/restfulie/common/builder/rules/link.rb +0 -20
  59. data/lib/restfulie/common/builder/rules/links.rb +0 -9
  60. data/lib/restfulie/common/builder/rules/member_rule.rb +0 -8
  61. data/lib/restfulie/common/builder/rules/namespace.rb +0 -35
  62. data/lib/restfulie/common/builder/rules/rules_base.rb +0 -77
  63. data/lib/restfulie/common/builder.rb +0 -17
  64. data/lib/vendor/atom/configuration.rb +0 -24
  65. data/lib/vendor/atom/pub.rb +0 -250
  66. data/lib/vendor/atom/xml/parser.rb +0 -373
  67. data/lib/vendor/atom.rb +0 -771
@@ -0,0 +1,7 @@
1
+ module Restfulie::Client
2
+ end
3
+ module Restfulie::Client::HTTP#:nodoc:
4
+ ::Hash.instance_eval {
5
+ include Restfulie::Client::HTTP::LinkRequestBuilder
6
+ }
7
+ end
@@ -6,9 +6,9 @@ end
6
6
  adapter
7
7
  cache
8
8
  marshal
9
- link
10
9
  atom_ext
11
- xml
10
+ xml_ext
11
+ core_ext
12
12
  ).each do |file|
13
13
  require "restfulie/client/http/#{file}"
14
14
  end
@@ -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
@@ -6,6 +6,7 @@ module Restfulie::Client; end
6
6
  http
7
7
  configuration
8
8
  base
9
+ mikyung
9
10
  ).each do |file|
10
11
  require "restfulie/client/#{file}"
11
12
  end
@@ -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,11 @@
1
+ #initialize namespace
2
+ module Restfulie::Common::Converter; end
3
+
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)
11
+ 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
+
@@ -0,0 +1,5 @@
1
+ %w(
2
+ proc
3
+ ).each do |file|
4
+ require File.join(File.dirname(__FILE__), 'core_ext', file)
5
+ end
@@ -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