apipie-rails 0.0.11 → 0.0.12

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 (41) hide show
  1. data/README.rdoc +8 -10
  2. data/app/controllers/apipie/apipies_controller.rb +12 -4
  3. data/app/views/apipie/apipies/_disqus.html.erb +11 -0
  4. data/app/views/apipie/apipies/apipie_404.html.erb +12 -0
  5. data/app/views/apipie/apipies/method.html.erb +1 -1
  6. data/app/views/apipie/apipies/resource.html.erb +1 -1
  7. data/app/views/layouts/apipie/apipie.html.erb +4 -15
  8. data/lib/apipie-rails.rb +1 -0
  9. data/lib/apipie/apipie_module.rb +10 -2
  10. data/lib/apipie/client/base.rb +131 -0
  11. data/lib/apipie/client/{template/cli_command.rb.tt → cli_command.rb} +21 -22
  12. data/lib/apipie/client/generator.rb +33 -30
  13. data/lib/apipie/client/{template/bin.rb.tt → main.rb} +13 -30
  14. data/lib/apipie/client/{template/rest_client_oauth.rb.tt → rest_client_oauth.rb} +1 -11
  15. data/lib/apipie/client/template/{client.gemspec.tt → a_name.gemspec.tt} +1 -0
  16. data/lib/apipie/client/template/bin/bin.rb.tt +30 -0
  17. data/lib/apipie/client/template/lib/a_name.rb.tt +27 -0
  18. data/lib/apipie/client/template/{cli.rb.tt → lib/a_name/commands/cli.rb.tt} +5 -8
  19. data/lib/apipie/client/template/lib/a_name/config.yml +6 -0
  20. data/lib/apipie/client/template/lib/a_name/resources/resource.rb.tt +22 -0
  21. data/lib/apipie/client/template/{version.rb.tt → lib/a_name/version.rb.tt} +0 -0
  22. data/lib/apipie/client/thor.rb +19 -0
  23. data/lib/apipie/dsl_definition.rb +3 -3
  24. data/lib/apipie/errors.rb +38 -0
  25. data/lib/apipie/helpers.rb +17 -0
  26. data/lib/apipie/param_description.rb +19 -10
  27. data/lib/apipie/resource_description.rb +2 -2
  28. data/lib/apipie/validator.rb +13 -33
  29. data/lib/apipie/version.rb +1 -1
  30. data/lib/tasks/apipie.rake +5 -0
  31. data/rubygem-apipie-rails.spec +80 -41
  32. data/spec/controllers/users_controller_spec.rb +20 -17
  33. data/spec/dummy/app/controllers/users_controller.rb +1 -0
  34. data/spec/dummy/app/views/layouts/application.html.erb +14 -7
  35. data/spec/dummy/config/initializers/apipie.rb +15 -0
  36. data/spec/lib/param_description_spec.rb +0 -0
  37. data/spec/lib/parameter_description_spec.rb +41 -0
  38. metadata +50 -40
  39. data/lib/apipie/client/template/base.rb.tt +0 -55
  40. data/lib/apipie/client/template/client.rb.tt +0 -13
  41. data/lib/apipie/client/template/resource.rb.tt +0 -19
@@ -1,14 +1,7 @@
1
- #!/usr/bin/env ruby
2
- require "rubygems" # ruby1.9 doesn't "require" it though
3
- require "pathname"
4
- require "thor"
5
- require 'thor/core_ext/file_binary_read'
1
+ require "apipie/client/thor"
2
+ require "apipie/client/cli_command"
6
3
 
7
- $: << File.expand_path("../../lib", __FILE__)
8
- require "<%= name %><%= suffix %>"
9
- require "<%= name %><%= suffix %>/cli_command"
10
-
11
- module <%= class_base %>Cli
4
+ module Apipie::Client
12
5
  class Main < Thor
13
6
 
14
7
  def help(meth = nil)
@@ -18,7 +11,7 @@ module <%= class_base %>Cli
18
11
  self.class.handle_no_task_error(task, false) if klass.nil?
19
12
  klass.start(["-h", task].compact, :shell => self.shell)
20
13
  else
21
- say "<%= name.capitalize %> CLI"
14
+ say "#{apipie_options[:name].capitalize} CLI"
22
15
  say
23
16
  invoke :commands
24
17
  end
@@ -35,14 +28,14 @@ module <%= class_base %>Cli
35
28
  private
36
29
  def dispatch(task, given_args, given_options, config)
37
30
  parser = Thor::Options.new :auth => Thor::Option.parse(%w[auth -a], :string)
38
- opts = parser.parse(given_args)
31
+ opts = parser.parse(given_args)
39
32
  if opts['auth']
40
- username, password = opts['auth'].split(':')
41
- <%= class_base %><%= class_suffix %>.client_config[:username] = username
42
- <%= class_base %><%= class_suffix %>.client_config[:password] = password
33
+ username, password = opts['auth'].split(':')
34
+ apipie_options[:config][:username] = username
35
+ apipie_options[:config][:password] = password
43
36
  end
44
- #remaining = parser.instance_variable_get("@unknown") # TODO: this is an ugly hack :(
45
37
  remaining = parser.remaining
38
+
46
39
  super(task, remaining, given_options, config)
47
40
  end
48
41
  end
@@ -71,18 +64,18 @@ module <%= class_base %>Cli
71
64
  end
72
65
 
73
66
  def thorfiles
74
- Dir[File.expand_path("../../lib/<%= name %><%= suffix %>/commands/*.thor", __FILE__)]
67
+ Dir[File.expand_path("*/commands/*.thor", apipie_options[:root])]
75
68
  end
76
69
 
77
70
  # Display information about the given klasses. If with_module is given,
78
71
  # it shows a table with information extracted from the yaml file.
79
72
  #
80
73
  def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
81
- klasses -= [Thor, Main, ::<%= class_base %><%= class_suffix %>::CliCommand] unless show_internal
74
+ klasses -= [Thor, Main, ::Apipie::Client::CliCommand, ::Thor] unless show_internal
82
75
 
83
76
  show_modules if with_modules && !thor_yaml.empty?
84
77
 
85
- list = Hash.new { |h,k| h[k] = [] }
78
+ list = Hash.new { |h, k| h[k] = [] }
86
79
  groups = []
87
80
 
88
81
  # Get classes which inherit from Thor
@@ -93,7 +86,7 @@ module <%= class_base %>Cli
93
86
  list["root"] = groups
94
87
 
95
88
  # Order namespaces with default coming first
96
- list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
89
+ list = list.sort { |a, b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
97
90
  list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
98
91
  end
99
92
 
@@ -104,13 +97,3 @@ module <%= class_base %>Cli
104
97
 
105
98
  end
106
99
 
107
- begin
108
- <%= class_base %>Cli::Main.start
109
- rescue RestClient::Exception => e
110
- $stderr.puts e.message
111
- exit 1
112
- rescue Errno::ECONNREFUSED => e
113
- $stderr.puts "Server #{<%= class_base %><%= class_suffix %>.client_config[:base_url]} not available"
114
- $stderr.puts e.message
115
- exit 1
116
- end
@@ -9,17 +9,7 @@ unless RestClient.const_defined? :OAUTH_EXTENSION
9
9
  options = default_options.merge args[:oauth][:options] || { }
10
10
  consumer = OAuth::Consumer.new(args[:oauth][:consumer_key], args[:oauth][:consumer_secret], options)
11
11
 
12
-
13
- method_to_http_request = { :get => Net::HTTP::Get,
14
- :post => Net::HTTP::Post,
15
- :put => Net::HTTP::Put,
16
- :delete => Net::HTTP::Delete }
17
-
18
- http_request = method_to_http_request[args[:method]].
19
- new(args[:url]) # create Net::HTTPRequest to get oauth header,
20
- # because RestClient::Request is not supported by Oauth
21
- consumer.sign!(http_request)
22
- request['Authorization'] = http_request['Authorization'] # add oauth header to rest_client request
12
+ consumer.sign!(request)
23
13
  end
24
14
  end
25
15
  end
@@ -16,6 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.version = <%= class_base %><%= class_suffix %>::VERSION
17
17
 
18
18
  <% if all? %>gem.add_dependency 'thor', '>= 0.15.4'<% end %>
19
+ gem.add_dependency 'apipie-rails', '~> <%= Apipie::VERSION %>'
19
20
  gem.add_dependency 'json'
20
21
  gem.add_dependency 'rest-client', '>= 1.6.1'
21
22
  gem.add_dependency 'oauth'
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems" # ruby1.9 doesn't "require" it though
3
+ require "pathname"
4
+ require "thor"
5
+ require 'thor/core_ext/file_binary_read'
6
+
7
+ load_path = File.expand_path("../../lib", __FILE__)
8
+ $: << load_path unless $:.include?(load_path)
9
+
10
+ name, suffix = "<%= name %>", "<%= suffix %>"
11
+
12
+ require name + suffix
13
+ require 'apipie/client/main'
14
+
15
+ client_module = Object.const_get "<%= class_base %><%= class_suffix %>"
16
+
17
+ begin
18
+ Apipie::Client::Main.apipie_options = { :name => name,
19
+ :config => client_module.client_config,
20
+ :client_module => client_module,
21
+ :root => client_module.root }
22
+ Apipie::Client::Main.start
23
+ rescue RestClient::Exception => e
24
+ $stderr.puts e.message
25
+ exit 1
26
+ rescue Errno::ECONNREFUSED => e
27
+ $stderr.puts "Server #{client_module.client_config[:base_url]} not available"
28
+ $stderr.puts e.message
29
+ exit 1
30
+ end
@@ -0,0 +1,27 @@
1
+ require 'apipie/client/base'
2
+ require 'json'
3
+ require 'yaml'
4
+
5
+ Object.const_set("<%= class_base + class_suffix %>", client_module = Module.new do
6
+ def self.client_config
7
+ @client_config ||= YAML.load_file("#{root}/#{name}/config.yml")
8
+ end
9
+
10
+ def self.root
11
+ @root ||= File.expand_path(File.dirname(__FILE__))
12
+ end
13
+
14
+ def self.name
15
+ "<%= name %><%= suffix %>"
16
+ end
17
+
18
+ def self.doc
19
+ @doc ||= File.open("#{root}/#{name}/documentation.json", 'r') do |f|
20
+ JSON.load(f.read)['docs']
21
+ end
22
+ end
23
+ end)
24
+
25
+ require '<%= name %><%= suffix %>/version'
26
+ resource_files = Dir[File.expand_path("#{client_module.root}/#{client_module.name}/resources/*.rb", __FILE__)]
27
+ resource_files.each { |f| require f }
@@ -1,4 +1,4 @@
1
- class <%= resource_name.camelize %> < <%= class_base %><%= class_suffix %>::CliCommand
1
+ class <%= resource_name.camelize %> < Apipie::Client::CliCommand
2
2
 
3
3
  <% resource[:methods].each do |method| -%>
4
4
  desc '<%= method[:name] %>', '<%= api(method)[:short_description] %>'
@@ -9,15 +9,12 @@ class <%= resource_name.camelize %> < <%= class_base %><%= class_suffix %>::CliC
9
9
  method_option :<%= param[:name] %>, :required => <%= param[:required] ? 'true' : 'false' %>, :desc => '<%= plaintext(param[:description]) %>', :type => :<%= param[:expected_type] %>
10
10
  <% end -%>
11
11
  def <%= method[:name] %>
12
- <% if params_in_path(method).any? || transformation_hash(method).any?
12
+ <% #if params_in_path(method).any? || transformation_hash(method).any?
13
13
  transform_options_params = [params_in_path(method).inspect]
14
14
  transform_options_params << transformation_hash(method).inspect if transformation_hash(method).any? -%>
15
- <%= (params_in_path(method) + ["options"]).join(", ") %>, *_ = transform_options(<%= transform_options_params.join(", ").html_safe %>)
16
- <% end
17
-
18
- client_args = params_in_path(method).dup
19
- client_args << "options" if method[:params].any? -%>
20
- data, resp = client.<%= method[:name] %><%= "(#{client_args.join(", ")})" if client_args.any? %>
15
+ params = transform_options(<%= transform_options_params.join(", ").html_safe %>)
16
+ <% #end -%>
17
+ data, resp = client.<%= method[:name] %>(params)
21
18
  print_data(data)
22
19
  end
23
20
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ :base_url: http://localhost:3000
3
+ :enable_validations: false
4
+ :oauth:
5
+ :consumer_key: consumer
6
+ :consumer_secret: shhhh
@@ -0,0 +1,22 @@
1
+ module <%= class_base %><%= class_suffix %>
2
+ module Resources
3
+ class <%= resource_name.camelize %> < Apipie::Client::Base
4
+ def self.doc
5
+ @doc ||= <%= class_base %><%= class_suffix %>.doc['resources']["<%= resource_key %>"]
6
+ end
7
+ <% resource[:methods].each do |method| -%>
8
+
9
+ # @param [Hash] params a hash of params to be passed to the service
10
+ # allowed keys are: <%= validation(method).inspect %>
11
+ #
12
+ # @param [Hash] headers additional http headers
13
+ def <%= method[:name] %>(params = { }, headers = { })
14
+ check_params params, :allowed => <%= method[:params].any? %>, :method => __method__
15
+ url, params = fill_params_in_url "<%= api(method)[:api_url] %>", params
16
+ call(:"<%= api(method)[:http_method].downcase %>", url, params, headers)
17
+ end
18
+ <% end -%>
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Apipie::Client
2
+ class Thor < ::Thor
3
+
4
+ def self.apipie_options
5
+ Apipie::Client::Thor.instance_variable_get :@apipie_options
6
+ end
7
+
8
+ no_tasks do
9
+ def apipie_options
10
+ self.class.apipie_options
11
+ end
12
+ end
13
+
14
+ def self.apipie_options=(options)
15
+ Apipie::Client::Thor.instance_variable_set :@apipie_options, options
16
+ end
17
+
18
+ end
19
+ end
@@ -97,9 +97,9 @@ module Apipie
97
97
  # puts greeting
98
98
  # end
99
99
  #
100
- def param(param_name, *args, &block) #:doc:
100
+ def param(param_name, validator, desc_or_options = nil, options = {}, &block) #:doc:
101
101
  return unless Apipie.active_dsl?
102
- Apipie.last_params << Apipie::ParamDescription.new(param_name, *args, &block)
102
+ Apipie.last_params << Apipie::ParamDescription.new(param_name, validator, desc_or_options, options, &block)
103
103
  end
104
104
 
105
105
  # create method api and redefine newly added method
@@ -125,7 +125,7 @@ module Apipie
125
125
 
126
126
  # check if required parameters are present
127
127
  if param.required && !params.has_key?(param.name)
128
- raise ArgumentError.new("Expecting #{param.name} parameter.")
128
+ raise ParamMissing.new(param.name)
129
129
  end
130
130
 
131
131
  # params validations
@@ -0,0 +1,38 @@
1
+ module Apipie
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ParamError < Error
7
+ end
8
+
9
+ # abstract
10
+ class DefinedParamError < ParamError
11
+ attr_accessor :param
12
+
13
+ def initialize(param)
14
+ @param = param
15
+ end
16
+ end
17
+
18
+ class ParamMissing < DefinedParamError
19
+ def to_s
20
+ "Missing parameter #{@param}"
21
+ end
22
+ end
23
+
24
+ class ParamInvalid < DefinedParamError
25
+ attr_accessor :value, :error
26
+
27
+ def initialize(param, value, error)
28
+ super param
29
+ @value = value
30
+ @error = error
31
+ end
32
+
33
+ def to_s
34
+ "Invalid parameter '#{@param}' value #{@value.inspect}: #{@error}"
35
+ end
36
+ end
37
+
38
+ end
@@ -20,5 +20,22 @@ module Apipie
20
20
  ret.sub!(/\/*\Z/,"")
21
21
  ret
22
22
  end
23
+
24
+ def include_javascripts
25
+ %w[ bundled/jquery-1.7.2.js
26
+ bundled/bootstrap-collapse.js
27
+ bundled/prettify.js
28
+ apipie.js ].map do |file|
29
+ "<script type='text/javascript' src='#{Apipie.full_url("javascripts/#{file}")}'></script>"
30
+ end.join("\n").html_safe
31
+ end
32
+
33
+ def include_stylesheets
34
+ %w[ bundled/bootstrap.min.css
35
+ bundled/prettify.css
36
+ bundled/bootstrap-responsive.min.css ].map do |file|
37
+ "<link type='text/css' rel='stylesheet' href='#{Apipie.full_url("stylesheets/#{file}")}'/>"
38
+ end.join("\n").html_safe
39
+ end
23
40
  end
24
41
  end
@@ -12,24 +12,31 @@ module Apipie
12
12
 
13
13
  attr_accessor :parent
14
14
 
15
- def initialize(name, *args, &block)
15
+ def initialize(name, validator, desc_or_options = nil, options = {}, &block)
16
16
 
17
- if args.size > 1 || !args.first.is_a?(Hash)
18
- validator_type = args.shift || nil
19
- else
20
- validator_type = nil
17
+ if desc_or_options.is_a?(Hash) && options.empty?
18
+ options = desc_or_options
19
+ elsif desc_or_options.is_a?(String)
20
+ options[:desc] = desc_or_options
21
+ elsif !desc_or_options.nil?
22
+ raise ArgumentError.new("param description: expected description or options as 3rd parameter")
21
23
  end
22
- options = args.pop || {}
24
+
25
+ options.symbolize_keys!
23
26
 
24
27
  @name = name
25
28
  @desc = Apipie.markup_to_html(options[:desc] || '')
26
- @required = options[:required] || false
29
+ @required = if options.has_key? :required
30
+ options[:required]
31
+ else
32
+ Apipie.configuration.required_by_default?
33
+ end
27
34
  @allow_nil = options[:allow_nil] || false
28
35
 
29
36
  @validator = nil
30
- unless validator_type.nil?
37
+ unless validator.nil?
31
38
  @validator =
32
- Validator::BaseValidator.find(self, validator_type, options, block)
39
+ Validator::BaseValidator.find(self, validator, options, block)
33
40
  raise "Validator not found." unless validator
34
41
  end
35
42
  end
@@ -37,7 +44,9 @@ module Apipie
37
44
  def validate(value)
38
45
  return true if @allow_nil && value.nil?
39
46
  unless @validator.valid?(value)
40
- raise ArgumentError.new(@validator.error)
47
+ error = @validator.error
48
+ error = ParamError.new(error) unless error.is_a? Exception
49
+ raise error
41
50
  end
42
51
  end
43
52
 
@@ -31,8 +31,8 @@ module Apipie
31
31
  block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
32
32
  end
33
33
 
34
- def param(param_name, *args, &block)
35
- param_description = Apipie::ParamDescription.new(param_name, *args, &block)
34
+ def param(param_name, validator, desc_or_options = nil, options = {}, &block)
35
+ param_description = Apipie::ParamDescription.new(param_name, validator, desc_or_options, options, &block)
36
36
  @_params_ordered << param_description
37
37
  end
38
38
 
@@ -47,6 +47,10 @@ module Apipie
47
47
  "TODO: validator description"
48
48
  end
49
49
 
50
+ def error
51
+ ParamInvalid.new(param_name, @error_value, description)
52
+ end
53
+
50
54
  def to_s
51
55
  self.description
52
56
  end
@@ -83,12 +87,8 @@ module Apipie
83
87
  end
84
88
  end
85
89
 
86
- def error
87
- "Parameter #{param_name} expecting to be #{@type.name}, got: #{@error_value.class.name}"
88
- end
89
-
90
90
  def description
91
- "Parameter has to be #{@type}."
91
+ "Must be #{@type}"
92
92
  end
93
93
 
94
94
  def expected_type
@@ -118,12 +118,8 @@ module Apipie
118
118
  self.new(param_description, argument) if argument.is_a? Regexp
119
119
  end
120
120
 
121
- def error
122
- "Parameter #{param_name} expecting to match /#{@regexp.source}/, got '#{@error_value}'"
123
- end
124
-
125
121
  def description
126
- "Parameter has to match regular expression /#{@regexp.source}/."
122
+ "Must match regular expression /#{@regexp.source}/."
127
123
  end
128
124
  end
129
125
 
@@ -143,12 +139,8 @@ module Apipie
143
139
  self.new(param_description, argument) if argument.is_a?(Array)
144
140
  end
145
141
 
146
- def error
147
- "Parameter #{param_name} has bad value (#{@error_value.inspect}). Expecting one of: #{@array.join(',')}."
148
- end
149
-
150
142
  def description
151
- "Parameter has to be one of: #{@array.join(', ')}."
143
+ "Must be one of: #{@array.join(', ')}."
152
144
  end
153
145
  end
154
146
 
@@ -168,7 +160,7 @@ module Apipie
168
160
  end
169
161
 
170
162
  def error
171
- "Parameter #{param_name} has bad value (\"#{@error_value}\"). #{@help}"
163
+ ParamInvalid.new(param_name, @error_value, @help)
172
164
  end
173
165
 
174
166
  def description
@@ -202,16 +194,12 @@ module Apipie
202
194
  return true
203
195
  end
204
196
 
205
- def error
206
- "Has to be hash."
207
- end
208
-
209
197
  def description
210
- "Has to be hash."
198
+ "Must be a Hash"
211
199
  end
212
200
 
213
- def param(param_name, *args, &block)
214
- param_description = Apipie::ParamDescription.new(param_name, *args, &block)
201
+ def param(param_name, validator, desc_or_options = nil, options = {}, &block)
202
+ param_description = Apipie::ParamDescription.new(param_name, validator, desc_or_options, options, &block)
215
203
  param_description.parent = self.param_description
216
204
  @hash_params_ordered << param_description
217
205
  @hash_params[param_name.to_sym] = param_description
@@ -253,12 +241,8 @@ module Apipie
253
241
  end
254
242
  end
255
243
 
256
- def error
257
- "Parameter #{param_name} expecting to be a number, got: #{@error_value}"
258
- end
259
-
260
244
  def description
261
- "Has to be a number."
245
+ "Must be a number."
262
246
  end
263
247
 
264
248
  def self.validate(value)
@@ -278,12 +262,8 @@ module Apipie
278
262
  end
279
263
  end
280
264
 
281
- def error
282
- "Parameter #{param_name} expecting to be a boolean value, got: #{@error_value}"
283
- end
284
-
285
265
  def description
286
- "Has to be a boolean"
266
+ "Must be 'true' or 'false'"
287
267
  end
288
268
  end
289
269