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