restapi 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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