restapi 0.0.2 → 0.0.3

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.
@@ -1,7 +1,7 @@
1
1
  module Restapi
2
2
  module Helpers
3
- def rdoc
4
- @rdoc ||= RDoc::Markup::ToHtml.new
3
+ def markup_to_html(text)
4
+ Restapi.configuration.markup.to_html(text.strip_heredoc)
5
5
  end
6
6
 
7
7
  def full_url(path)
@@ -0,0 +1,45 @@
1
+ module Restapi
2
+
3
+ module Markup
4
+
5
+ class RDoc
6
+
7
+ def initialize
8
+ require 'rdoc'
9
+ require 'rdoc/markup/to_html'
10
+ @rdoc ||= ::RDoc::Markup::ToHtml.new
11
+ end
12
+
13
+ def to_html(text)
14
+ @rdoc.convert(text)
15
+ end
16
+
17
+ end
18
+
19
+ class Markdown
20
+
21
+ def initialize
22
+ require 'redcarpet'
23
+ @redcarpet ||= ::Redcarpet::Markdown.new(::Redcarpet::Render::HTML.new)
24
+ end
25
+
26
+ def to_html(text)
27
+ @redcarpet.render(text)
28
+ end
29
+
30
+ end
31
+
32
+ class Textile
33
+
34
+ def initialize
35
+ require 'RedCloth'
36
+ end
37
+
38
+ def to_html(text)
39
+ RedCloth.new(text).to_html
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -1,38 +1,104 @@
1
+ require 'set'
1
2
  module Restapi
2
-
3
+
3
4
  class MethodDescription
4
-
5
- attr_reader :errors, :params, :full_description, :method, :resource, :short_description, :path, :http
5
+
6
+ class Api
7
+
8
+ attr_accessor :short_description, :api_url, :http_method
9
+
10
+ def initialize(args)
11
+ @http_method = args[:method] || args[:http_method] || args[:http]
12
+ @short_description = args[:desc] || args[:short] || args[:description]
13
+ @api_url = create_api_url(args[:path] || args[:url])
14
+ end
15
+
16
+ private
17
+
18
+ def create_api_url(path)
19
+ "#{Restapi.configuration.api_base_url}#{path}"
20
+ end
21
+
22
+ end
23
+
24
+ attr_reader :errors, :full_description, :method, :resource, :apis
6
25
 
7
26
  def initialize(method, resource, app)
8
27
  @method = method
9
28
  @resource = resource
10
- args = app.get_api_args
11
- @short_description = args[:desc] || args[:short] || args[:description]
12
- @path = args[:path]
13
- @http = args[:method]
29
+
30
+ @apis = app.get_api_args
31
+
14
32
  desc = app.get_description || ''
15
- @full_description = Restapi.rdoc.convert(desc.strip_heredoc)
33
+ @full_description = Restapi.markup_to_html(desc)
16
34
  @errors = app.get_errors
17
- @params = app.get_params
35
+ @params_ordered = app.get_params
36
+
37
+ parent = @resource.controller.superclass
38
+ if parent != ActionController::Base
39
+ @parent_resource = parent.controller_name
40
+ end
41
+ @resource.add_method("#{resource._id}##{method}")
42
+ end
43
+
44
+ def params
45
+ params_ordered.reduce({}) { |h,p| h[p.name] = p; h }
46
+ end
47
+
48
+ def params_ordered
49
+ all_params = []
50
+ # get params from parent resource description
51
+ if @parent_resource
52
+ parent = Restapi.get_resource_description(@parent_resource)
53
+ merge_params(all_params, parent._params_ordered) if parent
54
+ end
55
+
56
+ # get params from actual resource description
57
+ if @resource
58
+ merge_params(all_params, resource._params_ordered)
59
+ end
60
+
61
+ merge_params(all_params, @params_ordered)
62
+ all_params.find_all(&:validator)
18
63
  end
19
64
 
20
- def doc_url; "#{Restapi.configuration.doc_base_url}/#{@resource}/#{@method}"; end
21
- def api_url; "#{Restapi.configuration.api_base_url}#{@path}"; end
65
+ def doc_url
66
+ [
67
+ ENV["RAILS_RELATIVE_URL_ROOT"],
68
+ Restapi.configuration.doc_base_url,
69
+ "##{@resource._id}/#{@method}"
70
+ ].join
71
+ end
72
+
73
+ def method_apis_to_json
74
+ @apis.each.collect do |api|
75
+ {
76
+ :api_url => api.api_url,
77
+ :http_method => api.http_method,
78
+ :short_description => api.short_description
79
+ }
80
+ end
81
+ end
22
82
 
23
83
  def to_json
24
84
  {
25
85
  :doc_url => doc_url,
26
- :api_url => api_url,
27
86
  :name => @method,
28
- :http_method => @http,
29
- :short_description => @short_description,
87
+ :apis => method_apis_to_json,
30
88
  :full_description => @full_description,
31
89
  :errors => @errors,
32
- :params => @params.collect { |_,v| v.to_json }
90
+ :params => params_ordered.map(&:to_json).flatten
33
91
  }
34
92
  end
35
93
 
94
+ private
95
+
96
+ def merge_params(params, new_params)
97
+ new_param_names = Set.new(new_params.map(&:name))
98
+ params.delete_if { |p| new_param_names.include?(p.name) }
99
+ params.concat(new_params)
100
+ end
101
+
36
102
  end
37
103
 
38
- end
104
+ end
@@ -9,6 +9,8 @@ module Restapi
9
9
  class ParamDescription
10
10
 
11
11
  attr_reader :name, :desc, :required, :validator
12
+
13
+ attr_accessor :parent
12
14
 
13
15
  def initialize(name, *args, &block)
14
16
 
@@ -20,12 +22,15 @@ module Restapi
20
22
  options = args.pop || {}
21
23
 
22
24
  @name = name
23
- @desc = Restapi.rdoc.convert((options[:desc] || '').strip_heredoc)
25
+ @desc = Restapi.markup_to_html(options[:desc] || '')
24
26
  @required = options[:required] || false
25
27
 
26
- @validator = Validator::BaseValidator.find(validator_type, options, block)
27
- raise "Validator not found." unless validator
28
- @validator.param_name = @name
28
+ @validator = nil
29
+ unless validator_type.nil?
30
+ @validator =
31
+ Validator::BaseValidator.find(self, validator_type, options, block)
32
+ raise "Validator not found." unless validator
33
+ end
29
34
  end
30
35
 
31
36
  def validate(value)
@@ -34,15 +39,35 @@ module Restapi
34
39
  end
35
40
  end
36
41
 
42
+ def full_name
43
+ name_parts = parents_and_self.map(&:name)
44
+ return ([name_parts.first] + name_parts[1..-1].map { |n| "[#{n}]" }).join("")
45
+ end
46
+
47
+ # returns an array of all the parents: starting with the root parent
48
+ # ending with itself
49
+ def parents_and_self
50
+ ret = []
51
+ if self.parent
52
+ ret.concat(self.parent.parents_and_self)
53
+ end
54
+ ret << self
55
+ ret
56
+ end
57
+
37
58
  def to_json
38
- {
39
- :name => name,
40
- :description => desc,
41
- :required => required,
42
- :validator => validator.to_s
43
- }
59
+ if validator.is_a? Restapi::Validator::HashValidator
60
+ validator.hash_params_ordered.map(&:to_json)
61
+ else
62
+ {
63
+ :name => full_name,
64
+ :description => desc,
65
+ :required => required,
66
+ :validator => validator.to_s
67
+ }
68
+ end
44
69
  end
45
70
 
46
71
  end
47
72
 
48
- end
73
+ end
@@ -10,12 +10,14 @@ module Restapi
10
10
  # id - resouce name
11
11
  class ResourceDescription
12
12
 
13
- attr_reader :_short_description, :_full_description, :_methods, :_id, :_path, :_version, :_name, :_params
13
+ attr_reader :controller, :_short_description, :_full_description, :_methods, :_id,
14
+ :_path, :_version, :_name, :_params_ordered
14
15
 
15
- def initialize(resource_name, &block)
16
+ def initialize(controller, resource_name, &block)
16
17
  @_methods = []
17
- @_params = Hash.new
18
+ @_params_ordered = []
18
19
 
20
+ @controller = controller
19
21
  @_id = resource_name
20
22
  @_version = "1"
21
23
  @_name = @_id.humanize
@@ -25,19 +27,24 @@ module Restapi
25
27
 
26
28
  block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
27
29
  end
28
-
30
+
29
31
  def param(param_name, *args, &block)
30
- @_params[param_name] = Restapi::ParamDescription.new(param_name, *args, &block)
32
+ param_description = Restapi::ParamDescription.new(param_name, *args, &block)
33
+ @_params_ordered << param_description
31
34
  end
32
35
 
33
36
  def path(path); @_path = path; end
37
+
34
38
  def version(version); @_version = version; end
39
+
35
40
  def name(name); @_name = name; end
41
+
36
42
  def short(short); @_short_description = short; end
37
43
  alias :short_description :short
44
+
38
45
  def desc(description)
39
46
  description ||= ''
40
- @_full_description = Restapi.rdoc.convert(description.strip_heredoc)
47
+ @_full_description = Restapi.markup_to_html(description)
41
48
  end
42
49
  alias :description :desc
43
50
  alias :full_description :desc
@@ -48,7 +55,10 @@ module Restapi
48
55
  @_methods.uniq!
49
56
  end
50
57
 
51
- def doc_url; "#{Restapi.configuration.doc_base_url}/#{@_id}"; end
58
+ def doc_url
59
+ "#{ENV["RAILS_RELATIVE_URL_ROOT"]}#{Restapi.configuration.doc_base_url}##{@_id}"
60
+ end
61
+
52
62
  def api_url; "#{Restapi.configuration.api_base_url}#{@_path}"; end
53
63
 
54
64
  def to_json(method_name = nil)
@@ -69,7 +79,5 @@ module Restapi
69
79
  :methods => _methods
70
80
  }
71
81
  end
72
-
73
82
  end
74
-
75
- end
83
+ end
@@ -1,7 +1,5 @@
1
1
  require "restapi/helpers"
2
2
  require "restapi/application"
3
- require "ostruct"
4
- require "erb"
5
3
 
6
4
  module Restapi
7
5
  extend Restapi::Helpers
@@ -28,14 +26,15 @@ module Restapi
28
26
  end
29
27
 
30
28
  class Configuration
31
- attr_accessor :app_name, :app_info, :copyright, :markup_language, :validate, :api_base_url, :doc_base_url
32
-
33
- def app_info=(text)
34
- @app_info = Restapi.rdoc.convert(text.strip_heredoc)
29
+ attr_accessor :app_name, :app_info, :copyright, :markup,
30
+ :validate, :api_base_url, :doc_base_url
31
+
32
+ def app_info
33
+ Restapi.markup_to_html(@app_info)
35
34
  end
36
35
 
37
36
  def initialize
38
- @markup_language = :rdoc
37
+ @markup = Restapi::Markup::RDoc.new
39
38
  @app_name = "Another API"
40
39
  @app_info = "Another API description"
41
40
  @copyright = nil
@@ -46,6 +46,8 @@ module Restapi
46
46
  case env['REQUEST_METHOD']
47
47
  when 'GET', 'HEAD'
48
48
  path = env['PATH_INFO'].sub("#{@baseurl}/","/restapi/").chomp('/')
49
+ path.sub!("#{ENV["RAILS_RELATIVE_URL_ROOT"]}",'')
50
+
49
51
  if match = @file_handler.match?(path)
50
52
  env["PATH_INFO"] = match
51
53
  return @file_handler.call(env)
@@ -6,12 +6,16 @@ module Restapi
6
6
  # and implement class method build and instance method validate
7
7
  class BaseValidator
8
8
 
9
- attr_accessor :param_name
9
+ attr_accessor :param_description
10
+
11
+ def initialize(param_description)
12
+ @param_description = param_description
13
+ end
10
14
 
11
15
  # find the right validator for given options
12
- def self.find(argument, options, block)
16
+ def self.find(param_description, argument, options, block)
13
17
  self.subclasses.each do |validator_type|
14
- validator = validator_type.build(argument, options, block)
18
+ validator = validator_type.build(param_description, argument, options, block)
15
19
  return validator if validator
16
20
  end
17
21
  return nil
@@ -28,6 +32,10 @@ module Restapi
28
32
  end
29
33
  end
30
34
 
35
+ def param_name
36
+ @param_description.name
37
+ end
38
+
31
39
  # validator description
32
40
  def description
33
41
  "TODO: validator description"
@@ -46,7 +54,8 @@ module Restapi
46
54
  # validate arguments type
47
55
  class TypeValidator < BaseValidator
48
56
 
49
- def initialize(argument)
57
+ def initialize(param_description, argument)
58
+ super(param_description)
50
59
  @type = argument
51
60
  @type = Integer if @type == Fixnum
52
61
  end
@@ -60,8 +69,8 @@ module Restapi
60
69
  end
61
70
  end
62
71
 
63
- def self.build(argument, options, block)
64
- self.new(argument) if argument.is_a?(Class) && argument != Hash
72
+ def self.build(param_description, argument, options, block)
73
+ self.new(param_description, argument) if argument.is_a?(Class) && (argument != Hash || block.nil?)
65
74
  end
66
75
 
67
76
  def error
@@ -76,7 +85,8 @@ module Restapi
76
85
  # validate arguments value with regular expression
77
86
  class RegexpValidator < BaseValidator
78
87
 
79
- def initialize(argument)
88
+ def initialize(param_description, argument)
89
+ super(param_description)
80
90
  @regexp = argument
81
91
  end
82
92
 
@@ -84,8 +94,8 @@ module Restapi
84
94
  value =~ @regexp
85
95
  end
86
96
 
87
- def self.build(argument, options, proc)
88
- self.new(argument) if argument.is_a? Regexp
97
+ def self.build(param_description, argument, options, proc)
98
+ self.new(param_description, argument) if argument.is_a? Regexp
89
99
  end
90
100
 
91
101
  def error
@@ -100,26 +110,17 @@ module Restapi
100
110
  # arguments value must be one of given in array
101
111
  class ArrayValidator < BaseValidator
102
112
 
103
- def initialize(argument)
113
+ def initialize(param_description, argument)
114
+ super(param_description)
104
115
  @array = argument
105
116
  end
106
117
 
107
118
  def validate(value)
108
-
109
- @array.find do |expected|
110
- expected_class = expected.class
111
- expected_class = Integer if expected_class == Fixnum
112
- begin
113
- converted_value = Kernel.send(expected_class.to_s, value)
114
- rescue ArgumentError
115
- false
116
- end
117
- converted_value === expected
118
- end
119
+ @array.include?(value)
119
120
  end
120
121
 
121
- def self.build(argument, options, proc)
122
- self.new(argument) if argument.is_a?(Array)
122
+ def self.build(param_description, argument, options, proc)
123
+ self.new(param_description, argument) if argument.is_a?(Array)
123
124
  end
124
125
 
125
126
  def error
@@ -133,7 +134,8 @@ module Restapi
133
134
 
134
135
  class ProcValidator < BaseValidator
135
136
 
136
- def initialize(argument)
137
+ def initialize(param_description, argument)
138
+ super(param_description)
137
139
  @proc = argument
138
140
  end
139
141
 
@@ -141,8 +143,8 @@ module Restapi
141
143
  (@help = @proc.call(value)) === true
142
144
  end
143
145
 
144
- def self.build(argument, options, proc)
145
- self.new(argument) if argument.is_a?(Proc) && argument.arity == 1
146
+ def self.build(param_description, argument, options, proc)
147
+ self.new(param_description, argument) if argument.is_a?(Proc) && argument.arity == 1
146
148
  end
147
149
 
148
150
  def error
@@ -156,12 +158,16 @@ module Restapi
156
158
 
157
159
  class HashValidator < BaseValidator
158
160
 
159
- def self.build(argument, options, block)
160
- self.new(block) if block.is_a?(Proc) && block.arity <= 0 && argument == Hash
161
+ attr_reader :hash_params_ordered
162
+
163
+ def self.build(param_description, argument, options, block)
164
+ self.new(param_description, block) if block.is_a?(Proc) && block.arity <= 0 && argument == Hash
161
165
  end
162
166
 
163
- def initialize(argument)
167
+ def initialize(param_description, argument)
168
+ super(param_description)
164
169
  @proc = argument
170
+ @hash_params_ordered = []
165
171
  @hash_params = {}
166
172
 
167
173
  self.instance_exec(&@proc)
@@ -185,9 +191,12 @@ module Restapi
185
191
  end
186
192
 
187
193
  def param(param_name, *args, &block)
188
- @hash_params[param_name.to_sym] = Restapi::ParamDescription.new(param_name, *args, &block)
194
+ param_description = Restapi::ParamDescription.new(param_name, *args, &block)
195
+ param_description.parent = self.param_description
196
+ @hash_params_ordered << param_description
197
+ @hash_params[param_name.to_sym] = param_description
189
198
  end
190
199
  end
191
200
 
192
201
  end
193
- end
202
+ end