restfulie 0.1.0.beta1 → 0.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.
- data/README.textile +87 -99
- data/Rakefile +14 -109
- data/lib/restfulie.rb +183 -23
- metadata +12 -197
- data/Gemfile +0 -28
- data/Gemfile.lock +0 -128
- data/LICENSE +0 -17
- data/lib/restfulie/client.rb +0 -26
- data/lib/restfulie/client/base.rb +0 -36
- data/lib/restfulie/client/cache.rb +0 -11
- data/lib/restfulie/client/cache/basic.rb +0 -76
- data/lib/restfulie/client/cache/fake.rb +0 -15
- data/lib/restfulie/client/cache/http_ext.rb +0 -123
- data/lib/restfulie/client/cache/restrictions.rb +0 -13
- data/lib/restfulie/client/configuration.rb +0 -67
- data/lib/restfulie/client/dsl.rb +0 -66
- data/lib/restfulie/client/entry_point.rb +0 -61
- data/lib/restfulie/client/ext/atom_ext.rb +0 -14
- data/lib/restfulie/client/ext/http_ext.rb +0 -22
- data/lib/restfulie/client/ext/json_ext.rb +0 -16
- data/lib/restfulie/client/feature.rb +0 -5
- data/lib/restfulie/client/feature/base.rb +0 -75
- data/lib/restfulie/client/feature/base_request.rb +0 -35
- data/lib/restfulie/client/feature/cache.rb +0 -16
- data/lib/restfulie/client/feature/enhance_response.rb +0 -12
- data/lib/restfulie/client/feature/follow_request.rb +0 -41
- data/lib/restfulie/client/feature/history.rb +0 -26
- data/lib/restfulie/client/feature/history_request.rb +0 -19
- data/lib/restfulie/client/feature/open_search.rb +0 -21
- data/lib/restfulie/client/feature/open_search/pattern_matcher.rb +0 -25
- data/lib/restfulie/client/feature/serialize_body.rb +0 -32
- data/lib/restfulie/client/feature/setup_header.rb +0 -22
- data/lib/restfulie/client/feature/throw_error.rb +0 -41
- data/lib/restfulie/client/feature/verb.rb +0 -119
- data/lib/restfulie/client/http.rb +0 -7
- data/lib/restfulie/client/http/cache.rb +0 -28
- data/lib/restfulie/client/http/error.rb +0 -77
- data/lib/restfulie/client/http/response_holder.rb +0 -29
- data/lib/restfulie/client/master_delegator.rb +0 -31
- data/lib/restfulie/client/mikyung.rb +0 -15
- data/lib/restfulie/client/mikyung/concatenator.rb +0 -18
- data/lib/restfulie/client/mikyung/core.rb +0 -70
- data/lib/restfulie/client/mikyung/languages.rb +0 -11
- data/lib/restfulie/client/mikyung/languages/german.rb +0 -24
- data/lib/restfulie/client/mikyung/languages/portuguese.rb +0 -23
- data/lib/restfulie/client/mikyung/rest_process_model.rb +0 -191
- data/lib/restfulie/client/mikyung/steady_state_walker.rb +0 -38
- data/lib/restfulie/client/mikyung/then_condition.rb +0 -39
- data/lib/restfulie/client/mikyung/when_condition.rb +0 -57
- data/lib/restfulie/common.rb +0 -18
- data/lib/restfulie/common/converter.rb +0 -43
- data/lib/restfulie/common/converter/atom.rb +0 -12
- data/lib/restfulie/common/converter/atom/base.rb +0 -91
- data/lib/restfulie/common/converter/atom/builder.rb +0 -111
- data/lib/restfulie/common/converter/atom/helpers.rb +0 -17
- data/lib/restfulie/common/converter/json.rb +0 -12
- data/lib/restfulie/common/converter/json/base.rb +0 -87
- data/lib/restfulie/common/converter/json/builder.rb +0 -102
- data/lib/restfulie/common/converter/json/helpers.rb +0 -17
- data/lib/restfulie/common/converter/open_search.rb +0 -16
- data/lib/restfulie/common/converter/open_search/descriptor.rb +0 -32
- data/lib/restfulie/common/converter/values.rb +0 -33
- data/lib/restfulie/common/converter/xml.rb +0 -14
- data/lib/restfulie/common/converter/xml/base.rb +0 -63
- data/lib/restfulie/common/converter/xml/builder.rb +0 -113
- data/lib/restfulie/common/converter/xml/helpers.rb +0 -17
- data/lib/restfulie/common/converter/xml/link.rb +0 -30
- data/lib/restfulie/common/converter/xml/links.rb +0 -21
- data/lib/restfulie/common/core_ext.rb +0 -1
- data/lib/restfulie/common/core_ext/hash.rb +0 -18
- data/lib/restfulie/common/error.rb +0 -19
- data/lib/restfulie/common/links.rb +0 -9
- data/lib/restfulie/common/logger.rb +0 -19
- data/lib/restfulie/common/representation.rb +0 -3
- data/lib/restfulie/common/representation/atom.rb +0 -20
- data/lib/restfulie/common/representation/atom/atom.rng +0 -597
- data/lib/restfulie/common/representation/atom/base.rb +0 -142
- data/lib/restfulie/common/representation/atom/category.rb +0 -41
- data/lib/restfulie/common/representation/atom/entry.rb +0 -59
- data/lib/restfulie/common/representation/atom/factory.rb +0 -43
- data/lib/restfulie/common/representation/atom/feed.rb +0 -110
- data/lib/restfulie/common/representation/atom/link.rb +0 -68
- data/lib/restfulie/common/representation/atom/person.rb +0 -48
- data/lib/restfulie/common/representation/atom/source.rb +0 -59
- data/lib/restfulie/common/representation/atom/tag_collection.rb +0 -38
- data/lib/restfulie/common/representation/atom/xml.rb +0 -90
- data/lib/restfulie/common/representation/generic.rb +0 -22
- data/lib/restfulie/common/representation/json.rb +0 -13
- data/lib/restfulie/common/representation/json/base.rb +0 -27
- data/lib/restfulie/common/representation/json/keys_as_methods.rb +0 -74
- data/lib/restfulie/common/representation/json/link.rb +0 -29
- data/lib/restfulie/common/representation/json/link_collection.rb +0 -23
- data/lib/restfulie/common/representation/links.rb +0 -11
- data/lib/restfulie/server.rb +0 -25
- data/lib/restfulie/server/action_controller.rb +0 -11
- data/lib/restfulie/server/action_controller/base.rb +0 -48
- data/lib/restfulie/server/action_controller/params_parser.rb +0 -100
- data/lib/restfulie/server/action_controller/patch.rb +0 -6
- data/lib/restfulie/server/action_controller/restful_responder.rb +0 -12
- data/lib/restfulie/server/action_controller/trait.rb +0 -9
- data/lib/restfulie/server/action_controller/trait/cacheable.rb +0 -81
- data/lib/restfulie/server/action_controller/trait/created.rb +0 -17
- data/lib/restfulie/server/action_view.rb +0 -10
- data/lib/restfulie/server/action_view/helpers.rb +0 -50
- data/lib/restfulie/server/action_view/template_handlers.rb +0 -30
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +0 -21
- data/lib/restfulie/server/configuration.rb +0 -24
- data/lib/restfulie/server/controller.rb +0 -74
- data/lib/restfulie/server/core_ext.rb +0 -1
- data/lib/restfulie/server/core_ext/array.rb +0 -61
- data/lib/restfulie/version.rb +0 -14
@@ -1,119 +0,0 @@
|
|
1
|
-
module Restfulie::Client::Feature::Verb
|
2
|
-
|
3
|
-
# GET HTTP verb without {Error}
|
4
|
-
# * <tt>path: '/posts'</tt>
|
5
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
6
|
-
def get(params = {})
|
7
|
-
@verb = :get
|
8
|
-
at query_string(params)
|
9
|
-
request_flow
|
10
|
-
end
|
11
|
-
|
12
|
-
# HEAD HTTP verb without {Error}
|
13
|
-
# * <tt>path: '/posts'</tt>
|
14
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
15
|
-
def head
|
16
|
-
@verb = :head
|
17
|
-
request_flow
|
18
|
-
end
|
19
|
-
|
20
|
-
# POST HTTP verb without {Error}
|
21
|
-
# * <tt>path: '/posts'</tt>
|
22
|
-
# * <tt>payload: 'some text'</tt>
|
23
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
24
|
-
def post(payload, options = {:recipe => nil})
|
25
|
-
@verb = :post
|
26
|
-
request_flow :body => payload
|
27
|
-
end
|
28
|
-
|
29
|
-
# PATCH HTTP verb without {Error}
|
30
|
-
# * <tt>path: '/posts'</tt>
|
31
|
-
# * <tt>payload: 'some text'</tt>
|
32
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
33
|
-
def patch(payload)
|
34
|
-
@verb = :patch
|
35
|
-
request_flow :body => payload
|
36
|
-
end
|
37
|
-
|
38
|
-
# PUT HTTP verb without {Error}
|
39
|
-
# * <tt>path: '/posts'</tt>
|
40
|
-
# * <tt>payload: 'some text'</tt>
|
41
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
42
|
-
def put(payload)
|
43
|
-
@verb = :put
|
44
|
-
request_flow :body => payload
|
45
|
-
end
|
46
|
-
|
47
|
-
# DELETE HTTP verb without {Error}
|
48
|
-
# * <tt>path: '/posts'</tt>
|
49
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
50
|
-
def delete
|
51
|
-
@verb = :delete
|
52
|
-
request_flow
|
53
|
-
end
|
54
|
-
|
55
|
-
# GET HTTP verb {Error}
|
56
|
-
# * <tt>path: '/posts'</tt>
|
57
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
58
|
-
def get!(params = {})
|
59
|
-
@verb = :get
|
60
|
-
at query_string(params)
|
61
|
-
request :throw_error
|
62
|
-
request_flow
|
63
|
-
end
|
64
|
-
|
65
|
-
# HEAD HTTP verb {Error}
|
66
|
-
# * <tt>path: '/posts'</tt>
|
67
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
68
|
-
def head!
|
69
|
-
@verb = :head
|
70
|
-
request :throw_error
|
71
|
-
request_flow
|
72
|
-
end
|
73
|
-
|
74
|
-
# POST HTTP verb {Error}
|
75
|
-
# * <tt>path: '/posts'</tt>
|
76
|
-
# * <tt>payload: 'some text'</tt>
|
77
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
78
|
-
def post!(payload, options = {:recipe => nil})
|
79
|
-
@verb = :post
|
80
|
-
request :throw_error
|
81
|
-
request_flow :body => payload
|
82
|
-
end
|
83
|
-
|
84
|
-
# PATCH HTTP verb {Error}
|
85
|
-
# * <tt>path: '/posts'</tt>
|
86
|
-
# * <tt>payload: 'some text'</tt>
|
87
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
88
|
-
def patch!(payload)
|
89
|
-
@verb = :patch
|
90
|
-
request :throw_error
|
91
|
-
request_flow :body => payload
|
92
|
-
end
|
93
|
-
|
94
|
-
# PUT HTTP verb {Error}
|
95
|
-
# * <tt>path: '/posts'</tt>
|
96
|
-
# * <tt>payload: 'some text'</tt>
|
97
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
98
|
-
def put!(payload)
|
99
|
-
@verb = :put
|
100
|
-
request :throw_error
|
101
|
-
request_flow :body => payload
|
102
|
-
end
|
103
|
-
|
104
|
-
# DELETE HTTP verb {Error}
|
105
|
-
# * <tt>path: '/posts'</tt>
|
106
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
107
|
-
def delete!
|
108
|
-
@verb = :delete
|
109
|
-
request :throw_error
|
110
|
-
request_flow
|
111
|
-
end
|
112
|
-
|
113
|
-
protected
|
114
|
-
|
115
|
-
def query_string(params)
|
116
|
-
params = params.map { |param, value| "#{param}=#{value}"}.join("&")
|
117
|
-
params.blank? ? "" : URI.escape("?#{params}")
|
118
|
-
end
|
119
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP
|
4
|
-
module Cache
|
5
|
-
def store
|
6
|
-
@store || @store = ::ActiveSupport::Cache::MemoryStore.new
|
7
|
-
end
|
8
|
-
|
9
|
-
def get
|
10
|
-
store.fetch(@uri) do
|
11
|
-
request(:get, @uri, @headers)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def head
|
16
|
-
store.fetch(@uri) do
|
17
|
-
request(:head, @uri, @headers)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class RequestBuilderExecutorWithCache < RequestBuilderExecutor
|
23
|
-
include Cache
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
@@ -1,77 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP#:nodoc:
|
4
|
-
#Client errors
|
5
|
-
module Error
|
6
|
-
# Standard error thrown on major client exceptions
|
7
|
-
class RESTError < StandardError
|
8
|
-
attr_reader :response
|
9
|
-
attr_reader :request
|
10
|
-
|
11
|
-
def initialize(request, response)
|
12
|
-
@request = request
|
13
|
-
@response = response
|
14
|
-
end
|
15
|
-
|
16
|
-
def to_s
|
17
|
-
"HTTP error #{@response.code} when invoking #{@request.host} via #{@response.method}. " +
|
18
|
-
((@response.body.blank?) ? "No additional data was sent." : "The complete response was:\n" + @response.body)
|
19
|
-
rescue
|
20
|
-
super
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class AutoFollowWithoutLocationError < RESTError; end
|
25
|
-
|
26
|
-
# Represents the HTTP code 503
|
27
|
-
class ServerNotAvailableError < RESTError
|
28
|
-
def initialize(request, response, exception)
|
29
|
-
super(request, response)
|
30
|
-
set_backtrace(exception.backtrace)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class UnknownError < RESTError; end
|
35
|
-
|
36
|
-
# Represents the HTTP code 300 range
|
37
|
-
class Redirection < RESTError; end
|
38
|
-
|
39
|
-
class ClientError < RESTError; end
|
40
|
-
|
41
|
-
# Represents the HTTP code 400
|
42
|
-
class BadRequest < ClientError; end
|
43
|
-
|
44
|
-
# Represents the HTTP code 401
|
45
|
-
class Unauthorized < ClientError; end
|
46
|
-
|
47
|
-
# Represents the HTTP code 403
|
48
|
-
class Forbidden < ClientError; end
|
49
|
-
|
50
|
-
# Represents the HTTP code 404
|
51
|
-
class NotFound < ClientError; end
|
52
|
-
|
53
|
-
# Represents the HTTP code 405
|
54
|
-
class MethodNotAllowed < ClientError; end
|
55
|
-
|
56
|
-
# Represents the HTTP code 412
|
57
|
-
class PreconditionFailed < ClientError; end
|
58
|
-
|
59
|
-
# Represents the HTTP code 407
|
60
|
-
class ProxyAuthenticationRequired < ClientError; end
|
61
|
-
|
62
|
-
# Represents the HTTP code 409
|
63
|
-
class Conflict < ClientError; end
|
64
|
-
|
65
|
-
# Represents the HTTP code 410
|
66
|
-
class Gone < ClientError; end
|
67
|
-
|
68
|
-
# Represents the HTTP code 500
|
69
|
-
class ServerError < RESTError; end
|
70
|
-
|
71
|
-
# Represents the HTTP code 501
|
72
|
-
class NotImplemented < ServerError; end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Restfulie::Client::HTTP
|
2
|
-
module ResponseHolder
|
3
|
-
attr_reader :response, :request
|
4
|
-
|
5
|
-
def resource
|
6
|
-
type = headers['content-type'] || response['Content-Type']
|
7
|
-
representation = Restfulie::Common::Converter.content_type_for(type[0]) || Restfulie::Common::Representation::Generic.new
|
8
|
-
representation.unmarshal(response.body)
|
9
|
-
end
|
10
|
-
|
11
|
-
def at(uri)
|
12
|
-
request.clone.at(uri)
|
13
|
-
end
|
14
|
-
|
15
|
-
def headers
|
16
|
-
response.to_hash
|
17
|
-
end
|
18
|
-
|
19
|
-
def results_from(request, response)
|
20
|
-
@request = request
|
21
|
-
@response = response
|
22
|
-
end
|
23
|
-
|
24
|
-
def verb
|
25
|
-
@request.verb
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
class MasterDelegator
|
2
|
-
|
3
|
-
alias_method :original_respond_to?, :respond_to?
|
4
|
-
|
5
|
-
def respond_to?(sym)
|
6
|
-
original_respond_to?(sym) || @requester.respond_to?(sym)
|
7
|
-
end
|
8
|
-
|
9
|
-
def method_missing(sym, *args, &block)
|
10
|
-
if original_respond_to?(sym)
|
11
|
-
result = super(sym, *args, &block)
|
12
|
-
elsif @requester.respond_to?(sym)
|
13
|
-
result = @requester.send(sym, *args, &block)
|
14
|
-
else
|
15
|
-
# let it go
|
16
|
-
return super(sym, *args, &block)
|
17
|
-
end
|
18
|
-
delegate_parse result
|
19
|
-
end
|
20
|
-
|
21
|
-
protected
|
22
|
-
|
23
|
-
def delegate(what, *args, &block)
|
24
|
-
delegate_parse @requester.send(what, *args, &block)
|
25
|
-
end
|
26
|
-
|
27
|
-
def delegate_parse(result)
|
28
|
-
(result == @requester) ? self : result
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
Dir["#{File.dirname(__FILE__)}/mikyung/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
|
5
|
-
end
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
# Restfulie::Mikyung entry point is based on its core
|
10
|
-
# implementation.
|
11
|
-
module Restfulie
|
12
|
-
class Mikyung < Restfulie::Client::Mikyung::Core
|
13
|
-
Restfulie::Common::Logger.logger.level = Logger::INFO
|
14
|
-
end
|
15
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
# Concatenates pure text in order to build messages
|
5
|
-
# that are used as patterns.
|
6
|
-
# Usage:
|
7
|
-
# When there is a machine
|
8
|
-
#
|
9
|
-
# Will invoke concatenate 'machine' with 'a' with 'is' with 'there'
|
10
|
-
class Concatenator
|
11
|
-
attr_reader :content
|
12
|
-
def initialize(content, *args)
|
13
|
-
@content = args.inject(content) { |buf, arg| buf << " " << arg.content }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
# iterates following a series of steps provided a goal and a starting uri.
|
5
|
-
#
|
6
|
-
# Restfulie::Client::Mikyung.achieve(objective).at(uri).run
|
7
|
-
#
|
8
|
-
# In order to implement your own walker, supply an object that respond to the move method.
|
9
|
-
# Check the run method code.
|
10
|
-
class Core
|
11
|
-
attr_reader :start, :goal, :walker, :accepts, :follow
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@walker = Restfulie::Client::Mikyung::SteadyStateWalker.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def walks_with(walker)
|
18
|
-
@walker = walker
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
# initializes with a goal in mind
|
23
|
-
def achieve(goal)
|
24
|
-
@goal = goal
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
def at(start)
|
29
|
-
@start = start
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def follow
|
34
|
-
@follow = true
|
35
|
-
self
|
36
|
-
end
|
37
|
-
|
38
|
-
def accepts(accepts)
|
39
|
-
@accepts = accepts
|
40
|
-
self
|
41
|
-
end
|
42
|
-
|
43
|
-
# keeps changing from a steady state to another until its goal has been achieved
|
44
|
-
def run
|
45
|
-
if @start.kind_of? String
|
46
|
-
client = Restfulie.at(@start)
|
47
|
-
client = client.follow if @follow
|
48
|
-
client = client.accepts(@accepts) if @accepts
|
49
|
-
@start = current = client.get
|
50
|
-
else
|
51
|
-
# probably configured thru the Rest Process Model class
|
52
|
-
@start = current = @goal.class.get_restfulie.get
|
53
|
-
end
|
54
|
-
|
55
|
-
# load the steps and scenario
|
56
|
-
@goal.steps
|
57
|
-
@goal.scenario
|
58
|
-
|
59
|
-
while(!@goal.completed?(current))
|
60
|
-
current = @walker.move(@goal, current, self)
|
61
|
-
end
|
62
|
-
current
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class UnableToAchieveGoalError < Restfulie::Common::Error::RestfulieError
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
module Languages
|
5
|
-
module German
|
6
|
-
def Wenn(concat, &block)
|
7
|
-
When(concat, &block)
|
8
|
-
end
|
9
|
-
def Und(concat, &block)
|
10
|
-
And(concat, &block)
|
11
|
-
end
|
12
|
-
def Aber(concat, &block)
|
13
|
-
But(concat, &block)
|
14
|
-
end
|
15
|
-
def Dann(concat, &block)
|
16
|
-
Then(concat, &block)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
|