restspec 0.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.
Files changed (202) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +21 -0
  3. data/.gitignore +23 -0
  4. data/.rspec +4 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +6 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +188 -0
  9. data/ROADMAP.md +11 -0
  10. data/Rakefile +20 -0
  11. data/bin/restspec +54 -0
  12. data/bin/templates/Gemfile +3 -0
  13. data/bin/templates/custom_macros.rb +3 -0
  14. data/bin/templates/restspec_config.rb +10 -0
  15. data/bin/templates/spec_helper.rb +19 -0
  16. data/docs/endpoints.md +200 -0
  17. data/docs/helpers.md +40 -0
  18. data/docs/macros.md +140 -0
  19. data/docs/matchers.md +38 -0
  20. data/docs/schemas.md +28 -0
  21. data/docs/tutorial.md +477 -0
  22. data/docs/types.md +134 -0
  23. data/examples/store-api-tests/.rspec +3 -0
  24. data/examples/store-api-tests/Gemfile +4 -0
  25. data/examples/store-api-tests/Gemfile.lock +70 -0
  26. data/examples/store-api-tests/spec/api/category_spec.rb +23 -0
  27. data/examples/store-api-tests/spec/api/product_spec.rb +55 -0
  28. data/examples/store-api-tests/spec/api/restspec/endpoints.rb +39 -0
  29. data/examples/store-api-tests/spec/api/restspec/requirements.rb +0 -0
  30. data/examples/store-api-tests/spec/api/restspec/restspec_config.rb +6 -0
  31. data/examples/store-api-tests/spec/api/restspec/schemas.rb +11 -0
  32. data/examples/store-api-tests/spec/spec_helper.rb +19 -0
  33. data/examples/store-api-tests/spec/support/custom_macros.rb +3 -0
  34. data/examples/store-api-tests/spec/support/custom_matchers.rb +0 -0
  35. data/examples/store-api/.editorconfig +24 -0
  36. data/examples/store-api/.rbenv-vars.example +3 -0
  37. data/examples/store-api/.rspec +4 -0
  38. data/examples/store-api/.ruby-version +1 -0
  39. data/examples/store-api/Gemfile +58 -0
  40. data/examples/store-api/Gemfile.lock +216 -0
  41. data/examples/store-api/Guardfile +39 -0
  42. data/examples/store-api/README.md +1 -0
  43. data/examples/store-api/Rakefile +6 -0
  44. data/examples/store-api/app/assets/images/.keep +0 -0
  45. data/examples/store-api/app/assets/javascripts/application.js +16 -0
  46. data/examples/store-api/app/assets/javascripts/categories.js.coffee +3 -0
  47. data/examples/store-api/app/assets/javascripts/products.js.coffee +3 -0
  48. data/examples/store-api/app/assets/stylesheets/application.css +15 -0
  49. data/examples/store-api/app/assets/stylesheets/categories.css.scss +3 -0
  50. data/examples/store-api/app/assets/stylesheets/products.css.scss +3 -0
  51. data/examples/store-api/app/assets/stylesheets/scaffolds.css.scss +69 -0
  52. data/examples/store-api/app/controllers/application_controller.rb +5 -0
  53. data/examples/store-api/app/controllers/categories_controller.rb +74 -0
  54. data/examples/store-api/app/controllers/concerns/.keep +0 -0
  55. data/examples/store-api/app/controllers/products_controller.rb +74 -0
  56. data/examples/store-api/app/helpers/application_helper.rb +2 -0
  57. data/examples/store-api/app/helpers/categories_helper.rb +2 -0
  58. data/examples/store-api/app/helpers/products_helper.rb +2 -0
  59. data/examples/store-api/app/mailers/.keep +0 -0
  60. data/examples/store-api/app/models/.keep +0 -0
  61. data/examples/store-api/app/models/category.rb +2 -0
  62. data/examples/store-api/app/models/concerns/.keep +0 -0
  63. data/examples/store-api/app/models/product.rb +3 -0
  64. data/examples/store-api/app/views/categories/_form.html.erb +21 -0
  65. data/examples/store-api/app/views/categories/edit.html.erb +6 -0
  66. data/examples/store-api/app/views/categories/index.html.erb +25 -0
  67. data/examples/store-api/app/views/categories/index.json.jbuilder +4 -0
  68. data/examples/store-api/app/views/categories/new.html.erb +5 -0
  69. data/examples/store-api/app/views/categories/show.html.erb +9 -0
  70. data/examples/store-api/app/views/categories/show.json.jbuilder +1 -0
  71. data/examples/store-api/app/views/layouts/application.html.erb +14 -0
  72. data/examples/store-api/app/views/products/_form.html.erb +29 -0
  73. data/examples/store-api/app/views/products/edit.html.erb +6 -0
  74. data/examples/store-api/app/views/products/index.html.erb +29 -0
  75. data/examples/store-api/app/views/products/index.json.jbuilder +4 -0
  76. data/examples/store-api/app/views/products/new.html.erb +5 -0
  77. data/examples/store-api/app/views/products/show.html.erb +19 -0
  78. data/examples/store-api/app/views/products/show.json.jbuilder +6 -0
  79. data/examples/store-api/bin/bundle +3 -0
  80. data/examples/store-api/bin/guard +16 -0
  81. data/examples/store-api/bin/rails +8 -0
  82. data/examples/store-api/bin/rake +8 -0
  83. data/examples/store-api/bin/spring +18 -0
  84. data/examples/store-api/config.ru +4 -0
  85. data/examples/store-api/config/application.rb +30 -0
  86. data/examples/store-api/config/boot.rb +4 -0
  87. data/examples/store-api/config/database.yml +25 -0
  88. data/examples/store-api/config/environment.rb +5 -0
  89. data/examples/store-api/config/environments/development.rb +37 -0
  90. data/examples/store-api/config/environments/production.rb +78 -0
  91. data/examples/store-api/config/environments/test.rb +39 -0
  92. data/examples/store-api/config/initializers/assets.rb +8 -0
  93. data/examples/store-api/config/initializers/backtrace_silencers.rb +7 -0
  94. data/examples/store-api/config/initializers/cookies_serializer.rb +3 -0
  95. data/examples/store-api/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/examples/store-api/config/initializers/inflections.rb +16 -0
  97. data/examples/store-api/config/initializers/mime_types.rb +4 -0
  98. data/examples/store-api/config/initializers/session_store.rb +3 -0
  99. data/examples/store-api/config/initializers/wrap_parameters.rb +14 -0
  100. data/examples/store-api/config/locales/en.yml +23 -0
  101. data/examples/store-api/config/routes.rb +59 -0
  102. data/examples/store-api/config/secrets.yml +22 -0
  103. data/examples/store-api/db/migrate/20141205154816_create_products.rb +11 -0
  104. data/examples/store-api/db/migrate/20141205171104_create_categories.rb +9 -0
  105. data/examples/store-api/db/migrate/20141205171140_add_category_id_to_products.rb +5 -0
  106. data/examples/store-api/db/schema.rb +31 -0
  107. data/examples/store-api/db/seeds.rb +7 -0
  108. data/examples/store-api/lib/assets/.keep +0 -0
  109. data/examples/store-api/lib/tasks/.keep +0 -0
  110. data/examples/store-api/log/.keep +0 -0
  111. data/examples/store-api/public/404.html +67 -0
  112. data/examples/store-api/public/422.html +67 -0
  113. data/examples/store-api/public/500.html +66 -0
  114. data/examples/store-api/public/favicon.ico +0 -0
  115. data/examples/store-api/public/robots.txt +5 -0
  116. data/examples/store-api/spec/controllers/categories_controller_spec.rb +159 -0
  117. data/examples/store-api/spec/controllers/products_controller_spec.rb +159 -0
  118. data/examples/store-api/spec/factories/categories.rb +6 -0
  119. data/examples/store-api/spec/factories/products.rb +8 -0
  120. data/examples/store-api/spec/helpers/categories_helper_spec.rb +15 -0
  121. data/examples/store-api/spec/helpers/products_helper_spec.rb +15 -0
  122. data/examples/store-api/spec/models/category_spec.rb +5 -0
  123. data/examples/store-api/spec/models/product_spec.rb +5 -0
  124. data/examples/store-api/spec/rails_helper.rb +50 -0
  125. data/examples/store-api/spec/requests/categories_spec.rb +10 -0
  126. data/examples/store-api/spec/requests/products_spec.rb +10 -0
  127. data/examples/store-api/spec/routing/categories_routing_spec.rb +35 -0
  128. data/examples/store-api/spec/routing/products_routing_spec.rb +35 -0
  129. data/examples/store-api/spec/spec_helper.rb +85 -0
  130. data/examples/store-api/spec/views/categories/edit.html.erb_spec.rb +18 -0
  131. data/examples/store-api/spec/views/categories/index.html.erb_spec.rb +19 -0
  132. data/examples/store-api/spec/views/categories/new.html.erb_spec.rb +18 -0
  133. data/examples/store-api/spec/views/categories/show.html.erb_spec.rb +14 -0
  134. data/examples/store-api/spec/views/products/edit.html.erb_spec.rb +24 -0
  135. data/examples/store-api/spec/views/products/index.html.erb_spec.rb +25 -0
  136. data/examples/store-api/spec/views/products/new.html.erb_spec.rb +24 -0
  137. data/examples/store-api/spec/views/products/show.html.erb_spec.rb +18 -0
  138. data/examples/store-api/vendor/assets/javascripts/.keep +0 -0
  139. data/examples/store-api/vendor/assets/stylesheets/.keep +0 -0
  140. data/lib/restspec.rb +38 -0
  141. data/lib/restspec/configuration.rb +43 -0
  142. data/lib/restspec/endpoints/dsl.rb +142 -0
  143. data/lib/restspec/endpoints/endpoint.rb +135 -0
  144. data/lib/restspec/endpoints/namespace.rb +89 -0
  145. data/lib/restspec/endpoints/network.rb +39 -0
  146. data/lib/restspec/endpoints/request.rb +11 -0
  147. data/lib/restspec/endpoints/response.rb +53 -0
  148. data/lib/restspec/requirements/dsl.rb +10 -0
  149. data/lib/restspec/requirements/requirement.rb +59 -0
  150. data/lib/restspec/rspec/api_helpers.rb +64 -0
  151. data/lib/restspec/rspec/api_macros.rb +126 -0
  152. data/lib/restspec/rspec/extras.rb +2 -0
  153. data/lib/restspec/rspec/matchers/api_matchers.rb +6 -0
  154. data/lib/restspec/rspec/matchers/be_like_schema.rb +18 -0
  155. data/lib/restspec/rspec/matchers/be_like_schema_array.rb +18 -0
  156. data/lib/restspec/rspec/matchers/have_header.rb +47 -0
  157. data/lib/restspec/rspec/matchers/have_status.rb +17 -0
  158. data/lib/restspec/rspec/matchers/include_where.rb +14 -0
  159. data/lib/restspec/rspec/shared_examples.rb +12 -0
  160. data/lib/restspec/schema/attribute.rb +31 -0
  161. data/lib/restspec/schema/attribute_example.rb +21 -0
  162. data/lib/restspec/schema/checker.rb +73 -0
  163. data/lib/restspec/schema/dsl.rb +36 -0
  164. data/lib/restspec/schema/schema.rb +21 -0
  165. data/lib/restspec/schema/schema_example.rb +28 -0
  166. data/lib/restspec/schema/types.rb +35 -0
  167. data/lib/restspec/schema/types/array_type.rb +34 -0
  168. data/lib/restspec/schema/types/basic_type.rb +35 -0
  169. data/lib/restspec/schema/types/boolean_type.rb +11 -0
  170. data/lib/restspec/schema/types/decimal_string_type.rb +32 -0
  171. data/lib/restspec/schema/types/decimal_type.rb +14 -0
  172. data/lib/restspec/schema/types/embedded_schema_type.rb +28 -0
  173. data/lib/restspec/schema/types/hash_type.rb +25 -0
  174. data/lib/restspec/schema/types/integer_type.rb +11 -0
  175. data/lib/restspec/schema/types/null_type.rb +11 -0
  176. data/lib/restspec/schema/types/one_of_type.rb +21 -0
  177. data/lib/restspec/schema/types/schema_id_type.rb +88 -0
  178. data/lib/restspec/schema/types/string_type.rb +11 -0
  179. data/lib/restspec/shortcuts.rb +8 -0
  180. data/lib/restspec/stores/endpoint_store.rb +25 -0
  181. data/lib/restspec/stores/namespace_store.rb +20 -0
  182. data/lib/restspec/stores/schema_store.rb +19 -0
  183. data/lib/restspec/values/status_code.rb +13 -0
  184. data/lib/restspec/values/super_hash.rb +12 -0
  185. data/lib/restspec/version.rb +3 -0
  186. data/restspec.gemspec +37 -0
  187. data/spec/restspec/endpoints/dsl_spec.rb +269 -0
  188. data/spec/restspec/endpoints/endpoint_spec.rb +146 -0
  189. data/spec/restspec/endpoints/namespace_spec.rb +143 -0
  190. data/spec/restspec/endpoints/response_spec.rb +49 -0
  191. data/spec/restspec/schema/attribute_example_spec.rb +35 -0
  192. data/spec/restspec/schema/dsl_spec.rb +78 -0
  193. data/spec/restspec/schema/schema_example_spec.rb +40 -0
  194. data/spec/restspec/schema/schema_spec.rb +11 -0
  195. data/spec/restspec/schema/types/array_type_spec.rb +56 -0
  196. data/spec/restspec/schema/types/basic_type_spec.rb +62 -0
  197. data/spec/restspec/schema/types/boolean_type_spec.rb +26 -0
  198. data/spec/restspec/schema/types/null_type_spec.rb +25 -0
  199. data/spec/restspec/schema/types/string_type_spec.rb +26 -0
  200. data/spec/restspec/values/status_code_spec.rb +13 -0
  201. data/spec/spec_helper.rb +23 -0
  202. metadata +484 -0
@@ -0,0 +1,18 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe "products/show", :type => :view do
4
+ before(:each) do
5
+ @product = assign(:product, Product.create!(
6
+ :name => "Name",
7
+ :code => "Code",
8
+ :price => "9.99"
9
+ ))
10
+ end
11
+
12
+ it "renders attributes in <p>" do
13
+ render
14
+ expect(rendered).to match(/Name/)
15
+ expect(rendered).to match(/Code/)
16
+ expect(rendered).to match(/9.99/)
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ require "restspec/version"
2
+
3
+ module Restspec
4
+ end
5
+
6
+ require 'active_support/core_ext/object'
7
+
8
+ require "restspec/values/status_code"
9
+ require "restspec/values/super_hash"
10
+
11
+ require "restspec/configuration"
12
+ require "restspec/stores/namespace_store"
13
+ require "restspec/stores/endpoint_store"
14
+ require "restspec/stores/schema_store"
15
+ require "restspec/shortcuts"
16
+
17
+ require "restspec/schema/checker"
18
+ require "restspec/schema/types"
19
+ require "restspec/schema/attribute"
20
+ require "restspec/schema/attribute_example"
21
+ require "restspec/schema/schema_example"
22
+ require "restspec/schema/schema"
23
+ require "restspec/schema/dsl"
24
+
25
+ require "restspec/endpoints/dsl"
26
+ require "restspec/endpoints/request"
27
+ require "restspec/endpoints/response"
28
+ require "restspec/endpoints/network"
29
+ require "restspec/endpoints/endpoint"
30
+ require "restspec/endpoints/namespace"
31
+
32
+ require "restspec/requirements/dsl"
33
+ require "restspec/requirements/requirement"
34
+
35
+ require "restspec/rspec/extras"
36
+ require "restspec/rspec/api_helpers"
37
+ require "restspec/rspec/api_macros"
38
+ require "restspec/rspec/shared_examples"
@@ -0,0 +1,43 @@
1
+ require 'active_support/configurable'
2
+
3
+ module Restspec
4
+ include ActiveSupport::Configurable
5
+
6
+ class << self
7
+ def configure
8
+ config.request = OpenStruct.new(headers: {})
9
+ config.request.headers['Content-Type'] = 'application/json'
10
+ config.request.headers['Accept'] = 'application/json'
11
+
12
+ config.custom = OpenStruct.new
13
+
14
+ yield config
15
+
16
+ populate_stores
17
+ end
18
+
19
+ def populate_stores
20
+ load_schemas
21
+ load_endpoint_definition
22
+ load_requirement_definition
23
+ end
24
+
25
+ private
26
+
27
+ def load_schemas
28
+ eval_file Schema::DSL.new, config.schema_definition
29
+ end
30
+
31
+ def load_endpoint_definition
32
+ eval_file Endpoints::DSL.new, config.endpoints_definition
33
+ end
34
+
35
+ def load_requirement_definition
36
+ eval_file Requirements::DSL.new, config.requirements_definition
37
+ end
38
+
39
+ def eval_file(object, file_name)
40
+ object.instance_eval(File.read(file_name)) if file_name.present?
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,142 @@
1
+ require 'active_support/inflector'
2
+
3
+ module Restspec
4
+ module Endpoints
5
+ HTTP_METHODS = [:get, :post, :put, :patch, :delete, :head]
6
+
7
+ class DSL
8
+ def namespace(name, base_path: nil, &block)
9
+ namespace = Namespace.create(name.to_s)
10
+ namespace.base_path = base_path
11
+ namespace_dsl = NamespaceDSL.new(namespace)
12
+ namespace_dsl.instance_eval(&block)
13
+ end
14
+
15
+ def resource(name, options = {}, &block)
16
+ namespace name, base_path: (options[:base_path] || "/#{name}") do
17
+ if self.namespace.schema_name.blank?
18
+ schema_name = name.to_s.singularize
19
+ schema(schema_name.to_sym)
20
+ end
21
+
22
+ instance_eval(&block)
23
+ end
24
+ end
25
+ end
26
+
27
+ class NamespaceDSL
28
+ attr_accessor :namespace, :endpoint_base_path, :resource_endpoint_base_path, :common_endpoints_config_block
29
+
30
+ def initialize(namespace)
31
+ self.namespace = namespace
32
+ self.resource_endpoint_base_path = ''
33
+ end
34
+
35
+ def endpoint(name, &block)
36
+ endpoint = Endpoint.new(name)
37
+ endpoint_dsl = EndpointDSL.new(endpoint)
38
+ namespace.add_endpoint(endpoint)
39
+
40
+ endpoint_dsl.instance_eval(&block)
41
+ endpoint_dsl.instance_eval(&common_endpoints_config_block)
42
+
43
+ Restspec::EndpointStore.store(endpoint)
44
+ end
45
+
46
+ HTTP_METHODS.each do |http_method|
47
+ define_method(http_method) do |name, path = '', &block|
48
+ endpoint(name) do
49
+ public_send(http_method, path)
50
+ instance_eval(&block) if block.present?
51
+ end
52
+ end
53
+ end
54
+
55
+ def member(base_path: nil, identifier_name: 'id', &block)
56
+ member_namespace = namespace.add_anonymous_children_namespace
57
+ member_namespace.base_path = base_path || "/:#{identifier_name}"
58
+ NamespaceDSL.new(member_namespace).instance_eval(&block)
59
+ end
60
+
61
+ def collection(base_path: nil, &block)
62
+ collection_namespace = namespace.add_anonymous_children_namespace
63
+ collection_namespace.base_path = base_path
64
+ NamespaceDSL.new(collection_namespace).instance_eval(&block)
65
+ end
66
+
67
+ def schema(name, schema_extensions = {})
68
+ namespace.schema_name = name
69
+ namespace.schema_extensions = schema_extensions
70
+ end
71
+
72
+ def all(&endpoints_config)
73
+ self.common_endpoints_config_block = endpoints_config
74
+ end
75
+
76
+ def url_param(param, &value_or_example_block)
77
+ all do
78
+ url_param(param, &value_or_example_block)
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def common_endpoints_config_block
85
+ @common_endpoints_config_block ||= (Proc.new {})
86
+ end
87
+ end
88
+
89
+ class EndpointDSL < Struct.new(:endpoint)
90
+ def method(method)
91
+ endpoint.method = method
92
+ end
93
+
94
+ def path(path)
95
+ endpoint.path = path
96
+ end
97
+
98
+ def schema(name, schema_extensions = {})
99
+ endpoint.schema_name = name
100
+ endpoint.schema_extensions = schema_extensions
101
+ end
102
+
103
+ def headers
104
+ endpoint.headers
105
+ end
106
+
107
+ def url_param(param, &value_or_type_block)
108
+ endpoint.add_url_param_block(param) do
109
+ value_or_type_context = ValueOrTypeContext.new
110
+ value_or_type = value_or_type_context.instance_eval(&value_or_type_block)
111
+
112
+ if value_or_type.is_a?(Restspec::Schema::Types::BasicType)
113
+ attribute = if endpoint.schema && endpoint.schema.attributes[param]
114
+ endpoint.schema.attributes[param]
115
+ else
116
+ Restspec::Schema::Attribute.new(param, value_or_type_context.integer)
117
+ end
118
+
119
+ value_or_type.example_for(attribute)
120
+ else
121
+ value_or_type
122
+ end
123
+ end
124
+ end
125
+
126
+ HTTP_METHODS.each do |http_method|
127
+ define_method(http_method) do |path|
128
+ self.method http_method
129
+ self.path path
130
+ end
131
+ end
132
+ end
133
+
134
+ class ValueOrTypeContext
135
+ Restspec::Schema::Types::ALL.each do |type_name, type_class|
136
+ define_method(type_name) do |options = {}|
137
+ type_class.new(options)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,135 @@
1
+ require 'httparty'
2
+
3
+ module Restspec
4
+ module Endpoints
5
+ class Endpoint < Struct.new(:name)
6
+ attr_accessor :method, :path, :namespace, :raw_url_params, :schema_extensions
7
+ attr_writer :schema_name
8
+ attr_reader :last_response, :last_request
9
+
10
+ PARAM_INTERPOLATION_REGEX = /:([\w]+)/
11
+
12
+ def execute(body: {}, url_params: {}, query_params: {})
13
+ full_url = build_full_url(url_params, query_params)
14
+ request = Request.new(method, full_url, full_headers, body)
15
+
16
+ Network.request(request).tap do |response|
17
+ self.last_request = inject_self_into(response, :endpoint)
18
+ self.last_request = inject_self_into(request, :endpoint)
19
+ end
20
+ end
21
+
22
+ def execute_once(body: {}, url_params: {}, query_params: {}, before: ->{ })
23
+ @executed_response ||= begin
24
+ before.call
25
+ execute(body: body, url_params: url_params, query_params: query_params)
26
+ end
27
+ end
28
+
29
+ def full_name
30
+ [namespace.try(:name), name].compact.join("/")
31
+ end
32
+
33
+ def schema_name
34
+ @schema_name || namespace.try(:schema_name)
35
+ end
36
+
37
+ def schema
38
+ @schema ||= begin
39
+ found_schema = schema_from_store
40
+ if found_schema.present?
41
+ found_schema.clone.extend_with(schema_extensions || {})
42
+ else
43
+ nil
44
+ end
45
+ end
46
+ end
47
+
48
+ def full_path
49
+ if namespace && in_member_or_collection?
50
+ "#{namespace.full_base_path}#{path}"
51
+ else
52
+ path
53
+ end
54
+ end
55
+
56
+ def headers
57
+ @headers ||= {}
58
+ end
59
+
60
+ def url_params
61
+ @url_params ||= Restspec::Values::SuperHash.new(calculate_url_params)
62
+ end
63
+
64
+ def add_url_param_block(param, &block)
65
+ raw_url_params[param] = Proc.new(&block)
66
+ end
67
+
68
+ def executed_url
69
+ last_request.url
70
+ end
71
+
72
+ private
73
+
74
+ attr_writer :last_response, :last_request
75
+
76
+ def schema_from_store
77
+ Restspec::SchemaStore.get(schema_name)
78
+ end
79
+
80
+ def inject_self_into(object, property)
81
+ object.tap { object.send(:"#{property}=", self) }
82
+ end
83
+
84
+ def build_full_url(url_params, query_params)
85
+ full_url_params = self.url_params.merge(Values::SuperHash.new(url_params))
86
+ build_url(full_url_params, query_params)
87
+ end
88
+
89
+ def raw_url_params
90
+ @raw_url_params ||= Restspec::Values::SuperHash.new
91
+ end
92
+
93
+ def in_member_or_collection?
94
+ namespace.anonymous?
95
+ end
96
+
97
+ def calculate_url_params
98
+ raw_url_params.inject({}) do |hash, (key, value)|
99
+ real_value = if value.respond_to?(:call)
100
+ value.call
101
+ else
102
+ value
103
+ end
104
+
105
+ hash.merge(key.to_sym => real_value)
106
+ end
107
+ end
108
+
109
+ def build_url(full_url_params, query_params)
110
+ query_string = query_params.to_param
111
+ full_query_string = query_string.present? ? "?#{query_string}" : ""
112
+
113
+ base_url + path_from_params(full_url_params) + full_query_string
114
+ end
115
+
116
+ def path_from_params(url_params)
117
+ full_path.gsub(PARAM_INTERPOLATION_REGEX) do
118
+ url_params[$1] || url_params[$1.to_sym]
119
+ end
120
+ end
121
+
122
+ def full_headers
123
+ config_headers.merge(headers)
124
+ end
125
+
126
+ def config_headers
127
+ Restspec.config.try(:request).try(:headers) || {}
128
+ end
129
+
130
+ def base_url
131
+ @base_url ||= (Restspec.config.base_url || '')
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,89 @@
1
+ module Restspec
2
+ module Endpoints
3
+ class Namespace
4
+ attr_accessor :base_path, :parent_namespace, :children_namespaces, :schema_extensions
5
+ attr_writer :schema_name
6
+ attr_reader :endpoints
7
+
8
+ def self.create(name = '')
9
+ namespace = new(name)
10
+ Stores::NamespaceStore.store(namespace)
11
+ namespace
12
+ end
13
+
14
+ def initialize(name = '')
15
+ self.name = name
16
+ self.endpoints = []
17
+ self.children_namespaces = []
18
+ end
19
+
20
+ def add_anonymous_children_namespace
21
+ anonymous_namespace = Namespace.create
22
+ anonymous_namespace.parent_namespace = self
23
+ children_namespaces << anonymous_namespace
24
+ anonymous_namespace
25
+ end
26
+
27
+ def add_endpoint(endpoint)
28
+ endpoint.namespace = self
29
+ endpoints << endpoint
30
+ endpoint
31
+ end
32
+
33
+ def get_endpoint(endpoint_name)
34
+ search_internal_endpoint(endpoint_name) || search_child_endpoint(endpoint_name)
35
+ end
36
+
37
+ def top_level_namespace?
38
+ parent_namespace.nil?
39
+ end
40
+
41
+ def full_base_path
42
+ if top_level_namespace?
43
+ base_path
44
+ else
45
+ parent_namespace.full_base_path + base_path
46
+ end
47
+ end
48
+
49
+ def schema_name
50
+ @schema_name || parent_namespace.try(:schema_name)
51
+ end
52
+
53
+ def name
54
+ if top_level_namespace?
55
+ @name
56
+ else
57
+ [parent_namespace.name, @name].reject(&:blank?).join('/')
58
+ end
59
+ end
60
+
61
+ def anonymous?
62
+ @name.blank?
63
+ end
64
+
65
+ private
66
+
67
+ attr_writer :name, :endpoints
68
+
69
+ def search_internal_endpoint(endpoint_name)
70
+ endpoints.find do |endpoint|
71
+ endpoint.name == endpoint_name
72
+ end
73
+ end
74
+
75
+ def search_child_endpoint(endpoint_name)
76
+ children_namespaces.each do |children_namespace|
77
+ child_endpoint = children_namespace.get_endpoint(endpoint_name)
78
+ return child_endpoint if child_endpoint.present?
79
+ end
80
+
81
+ return nil
82
+ end
83
+
84
+ def base_path
85
+ @base_path ||= ''
86
+ end
87
+ end
88
+ end
89
+ end