hoodoo 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/bin/hoodoo +5 -0
  3. data/lib/hoodoo.rb +27 -0
  4. data/lib/hoodoo/active.rb +32 -0
  5. data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
  6. data/lib/hoodoo/active/active_record/base.rb +81 -0
  7. data/lib/hoodoo/active/active_record/creator.rb +134 -0
  8. data/lib/hoodoo/active/active_record/dated.rb +343 -0
  9. data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
  10. data/lib/hoodoo/active/active_record/finder.rb +606 -0
  11. data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
  12. data/lib/hoodoo/active/active_record/secure.rb +431 -0
  13. data/lib/hoodoo/active/active_record/support.rb +106 -0
  14. data/lib/hoodoo/active/active_record/translated.rb +87 -0
  15. data/lib/hoodoo/active/active_record/uuid.rb +80 -0
  16. data/lib/hoodoo/active/active_record/writer.rb +321 -0
  17. data/lib/hoodoo/client.rb +23 -0
  18. data/lib/hoodoo/client/augmented_array.rb +29 -0
  19. data/lib/hoodoo/client/augmented_base.rb +168 -0
  20. data/lib/hoodoo/client/augmented_hash.rb +23 -0
  21. data/lib/hoodoo/client/client.rb +354 -0
  22. data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
  23. data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
  24. data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
  25. data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
  26. data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
  27. data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
  28. data/lib/hoodoo/client/headers.rb +269 -0
  29. data/lib/hoodoo/communicators.rb +23 -0
  30. data/lib/hoodoo/communicators/fast.rb +44 -0
  31. data/lib/hoodoo/communicators/pool.rb +601 -0
  32. data/lib/hoodoo/communicators/slow.rb +84 -0
  33. data/lib/hoodoo/data.rb +51 -0
  34. data/lib/hoodoo/data/resources/caller.rb +39 -0
  35. data/lib/hoodoo/data/resources/errors.rb +28 -0
  36. data/lib/hoodoo/data/resources/log.rb +31 -0
  37. data/lib/hoodoo/data/resources/session.rb +26 -0
  38. data/lib/hoodoo/data/types/error_primitive.rb +27 -0
  39. data/lib/hoodoo/data/types/permissions.rb +40 -0
  40. data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
  41. data/lib/hoodoo/data/types/permissions_full.rb +28 -0
  42. data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
  43. data/lib/hoodoo/discovery.rb +20 -0
  44. data/lib/hoodoo/errors.rb +19 -0
  45. data/lib/hoodoo/errors/error_descriptions.rb +229 -0
  46. data/lib/hoodoo/errors/errors.rb +322 -0
  47. data/lib/hoodoo/generator.rb +139 -0
  48. data/lib/hoodoo/logger.rb +23 -0
  49. data/lib/hoodoo/logger/fast_writer.rb +27 -0
  50. data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
  51. data/lib/hoodoo/logger/logger.rb +387 -0
  52. data/lib/hoodoo/logger/slow_writer.rb +49 -0
  53. data/lib/hoodoo/logger/writer_mixin.rb +52 -0
  54. data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
  55. data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
  56. data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
  57. data/lib/hoodoo/middleware.rb +33 -0
  58. data/lib/hoodoo/presenters.rb +45 -0
  59. data/lib/hoodoo/presenters/base.rb +281 -0
  60. data/lib/hoodoo/presenters/base_dsl.rb +519 -0
  61. data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
  62. data/lib/hoodoo/presenters/embedding.rb +232 -0
  63. data/lib/hoodoo/presenters/types/array.rb +118 -0
  64. data/lib/hoodoo/presenters/types/boolean.rb +26 -0
  65. data/lib/hoodoo/presenters/types/date.rb +26 -0
  66. data/lib/hoodoo/presenters/types/date_time.rb +26 -0
  67. data/lib/hoodoo/presenters/types/decimal.rb +47 -0
  68. data/lib/hoodoo/presenters/types/enum.rb +55 -0
  69. data/lib/hoodoo/presenters/types/field.rb +158 -0
  70. data/lib/hoodoo/presenters/types/float.rb +26 -0
  71. data/lib/hoodoo/presenters/types/hash.rb +361 -0
  72. data/lib/hoodoo/presenters/types/integer.rb +26 -0
  73. data/lib/hoodoo/presenters/types/object.rb +117 -0
  74. data/lib/hoodoo/presenters/types/string.rb +53 -0
  75. data/lib/hoodoo/presenters/types/tags.rb +24 -0
  76. data/lib/hoodoo/presenters/types/text.rb +26 -0
  77. data/lib/hoodoo/presenters/types/uuid.rb +54 -0
  78. data/lib/hoodoo/services.rb +34 -0
  79. data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
  80. data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
  81. data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
  82. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
  83. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
  84. data/lib/hoodoo/services/discovery/discovery.rb +186 -0
  85. data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
  86. data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
  87. data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
  88. data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
  89. data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
  90. data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
  91. data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
  92. data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
  93. data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
  94. data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
  95. data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
  96. data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
  97. data/lib/hoodoo/services/middleware/interaction.rb +127 -0
  98. data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
  99. data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
  100. data/lib/hoodoo/services/services/context.rb +153 -0
  101. data/lib/hoodoo/services/services/implementation.rb +132 -0
  102. data/lib/hoodoo/services/services/interface.rb +934 -0
  103. data/lib/hoodoo/services/services/permissions.rb +250 -0
  104. data/lib/hoodoo/services/services/request.rb +189 -0
  105. data/lib/hoodoo/services/services/response.rb +316 -0
  106. data/lib/hoodoo/services/services/service.rb +141 -0
  107. data/lib/hoodoo/services/services/session.rb +729 -0
  108. data/lib/hoodoo/utilities.rb +12 -0
  109. data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
  110. data/lib/hoodoo/utilities/utilities.rb +380 -0
  111. data/lib/hoodoo/utilities/uuid.rb +44 -0
  112. data/lib/hoodoo/version.rb +17 -0
  113. data/spec/active/active_record/base_spec.rb +57 -0
  114. data/spec/active/active_record/creator_spec.rb +88 -0
  115. data/spec/active/active_record/dated_spec.rb +248 -0
  116. data/spec/active/active_record/error_mapping_spec.rb +360 -0
  117. data/spec/active/active_record/finder_spec.rb +744 -0
  118. data/spec/active/active_record/search_helper_spec.rb +384 -0
  119. data/spec/active/active_record/secure_spec.rb +435 -0
  120. data/spec/active/active_record/support_spec.rb +225 -0
  121. data/spec/active/active_record/translated_spec.rb +19 -0
  122. data/spec/active/active_record/uuid_spec.rb +72 -0
  123. data/spec/active/active_record/writer_spec.rb +272 -0
  124. data/spec/alchemy/alchemy-amq.rb +33 -0
  125. data/spec/client/augmented_array_spec.rb +15 -0
  126. data/spec/client/augmented_base_spec.rb +50 -0
  127. data/spec/client/augmented_hash_spec.rb +15 -0
  128. data/spec/client/client_spec.rb +955 -0
  129. data/spec/client/endpoint/endpoint_spec.rb +70 -0
  130. data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
  131. data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
  132. data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
  133. data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
  134. data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
  135. data/spec/client/headers_spec.rb +172 -0
  136. data/spec/communicators/fast_spec.rb +9 -0
  137. data/spec/communicators/pool_spec.rb +339 -0
  138. data/spec/communicators/slow_spec.rb +15 -0
  139. data/spec/data/resources/caller_spec.rb +156 -0
  140. data/spec/data/resources/errors_spec.rb +22 -0
  141. data/spec/data/resources/log_spec.rb +20 -0
  142. data/spec/data/resources/session_spec.rb +15 -0
  143. data/spec/data/types/error_primitive_spec.rb +15 -0
  144. data/spec/data/types/permissions_defaults_spec.rb +25 -0
  145. data/spec/data/types/permissions_full_spec.rb +44 -0
  146. data/spec/data/types/permissions_resources_spec.rb +34 -0
  147. data/spec/data/types/permissions_spec.rb +37 -0
  148. data/spec/errors/error_descriptions_spec.rb +98 -0
  149. data/spec/errors/errors_spec.rb +346 -0
  150. data/spec/integration/service_actions_spec.rb +112 -0
  151. data/spec/logger/fast_writer_spec.rb +18 -0
  152. data/spec/logger/logger_spec.rb +259 -0
  153. data/spec/logger/slow_writer_spec.rb +144 -0
  154. data/spec/logger/writers/file_writer_spec.rb +37 -0
  155. data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
  156. data/spec/logger/writers/stream_writer_spec.rb +38 -0
  157. data/spec/presenters/base_dsl_spec.rb +111 -0
  158. data/spec/presenters/base_spec.rb +871 -0
  159. data/spec/presenters/common_resource_fields_spec.rb +30 -0
  160. data/spec/presenters/embedding_spec.rb +87 -0
  161. data/spec/presenters/types/array_spec.rb +249 -0
  162. data/spec/presenters/types/boolean_spec.rb +51 -0
  163. data/spec/presenters/types/date_spec.rb +57 -0
  164. data/spec/presenters/types/date_time_spec.rb +59 -0
  165. data/spec/presenters/types/decimal_spec.rb +58 -0
  166. data/spec/presenters/types/enum_spec.rb +71 -0
  167. data/spec/presenters/types/field_spec.rb +77 -0
  168. data/spec/presenters/types/float_spec.rb +50 -0
  169. data/spec/presenters/types/hash_spec.rb +1069 -0
  170. data/spec/presenters/types/integer_spec.rb +50 -0
  171. data/spec/presenters/types/object_spec.rb +177 -0
  172. data/spec/presenters/types/string_spec.rb +65 -0
  173. data/spec/presenters/types/tags_spec.rb +56 -0
  174. data/spec/presenters/types/text_spec.rb +50 -0
  175. data/spec/presenters/types/uuid_spec.rb +46 -0
  176. data/spec/presenters/walk_spec.rb +198 -0
  177. data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
  178. data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
  179. data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
  180. data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
  181. data/spec/services/discovery/discovery_spec.rb +73 -0
  182. data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
  183. data/spec/services/discovery/results/for_http_spec.rb +37 -0
  184. data/spec/services/discovery/results/for_local_spec.rb +21 -0
  185. data/spec/services/discovery/results/for_remote_spec.rb +15 -0
  186. data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
  187. data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
  188. data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
  189. data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
  190. data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
  191. data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
  192. data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
  193. data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
  194. data/spec/services/middleware/middleware_cors_spec.rb +93 -0
  195. data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
  196. data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
  197. data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
  198. data/spec/services/middleware/middleware_logging_spec.rb +356 -0
  199. data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
  200. data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
  201. data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
  202. data/spec/services/middleware/middleware_public_spec.rb +238 -0
  203. data/spec/services/middleware/middleware_spec.rb +1569 -0
  204. data/spec/services/middleware/string_inquirer_spec.rb +30 -0
  205. data/spec/services/services/application_spec.rb +74 -0
  206. data/spec/services/services/context_spec.rb +48 -0
  207. data/spec/services/services/implementation_spec.rb +45 -0
  208. data/spec/services/services/interface_spec.rb +262 -0
  209. data/spec/services/services/permissions_spec.rb +249 -0
  210. data/spec/services/services/request_spec.rb +95 -0
  211. data/spec/services/services/response_spec.rb +250 -0
  212. data/spec/services/services/session_spec.rb +432 -0
  213. data/spec/spec_helper.rb +298 -0
  214. data/spec/utilities/utilities_spec.rb +537 -0
  215. data/spec/utilities/uuid_spec.rb +20 -0
  216. metadata +615 -0
@@ -0,0 +1,519 @@
1
+ ########################################################################
2
+ # File:: base_dsl.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Implement a DSL used to define a schema for data rendering
6
+ # and validation.
7
+ # ----------------------------------------------------------------------
8
+ # 02-Dec-2014 (ADH): Merge of DocumentedDSL code into BaseDSL.
9
+ ########################################################################
10
+
11
+ module Hoodoo
12
+ module Presenters
13
+
14
+ # A mixin to be used by any presenter that wants to support the
15
+ # Hoodoo::Presenters family of schema DSL methods. See e.g.
16
+ # Hoodoo::Presenters::Base. Mixed in by e.g.
17
+ # Hoodoo::Presenters::Object so that an instance can nest
18
+ # definitions of fields inside itself using this DSL.
19
+ #
20
+ module BaseDSL
21
+
22
+ # Define a JSON object with the supplied name and options.
23
+ #
24
+ # +name+:: The JSON key.
25
+ # +options+:: Optional +Hash+ of options, e.g. :required => true
26
+ # &block:: Block declaring the fields making up the nested object
27
+ #
28
+ # Example - mandatory JSON field "currencies" would lead to an object
29
+ # which had the same fields as Hoodoo::Data::Types::Currency along with
30
+ # an up-to-32 character string with field name "notes", that field also
31
+ # being required. Whether or not the fields of the referenced Currency
32
+ # type are needed is up to the definition of that type. See #type for
33
+ # more information.
34
+ #
35
+ # class Wealthy < Hoodoo::Presenters::Base
36
+ # schema do
37
+ # object :currencies, :required => true do
38
+ # type :Currency
39
+ # string :notes, :required => true, :length => 32
40
+ # end
41
+ # end
42
+ # end
43
+ #
44
+ def object( name, options = {}, &block )
45
+ raise ArgumentError.new( 'Hoodoo::Presenters::Base#Object must have block' ) unless block_given?
46
+
47
+ obj = property( name, Hoodoo::Presenters::Object, options, &block )
48
+ internationalised() if obj.is_internationalised?()
49
+ end
50
+
51
+ # Define a JSON array with the supplied name and options. If there is
52
+ # a block provided, then more DSL calls inside the block define how each
53
+ # array entry must look; otherwise array entries are not validated /
54
+ # are undefined.
55
+ #
56
+ # When an array field uses +:required => true+, this only says that at
57
+ # least an empty array must be present, nothing more. If the array uses
58
+ # a block with fields that themselves are required, then this is only
59
+ # checked for if the array contains one or more entries (and is checked
60
+ # for each of those entries).
61
+ #
62
+ # +name+:: The JSON key
63
+ # +options+:: A +Hash+ of options, e.g. :required => true
64
+ # &block:: Optional block declaring the fields of each array item
65
+ #
66
+ # Example - mandatory JSON field "currencies" would lead to an array
67
+ # where each array entry contains the fields defined by
68
+ # Hoodoo::Data::Types::Currency along with an up-to-32 character string
69
+ # with field name "notes", that field also being required. Whether or not
70
+ # the fields of the referenced Currency type are needed is up to the
71
+ # definition of that type. See #type for more information.
72
+ #
73
+ # class VeryWealthy < Hoodoo::Presenters::Base
74
+ # schema do
75
+ # array :currencies, :required => true do
76
+ # type :Currency
77
+ # string :notes, :required => true, :length => 32
78
+ # end
79
+ # end
80
+ # end
81
+ #
82
+ def array( name, options = {}, &block )
83
+ ary = property( name, Hoodoo::Presenters::Array, options, &block )
84
+ internationalised() if ary.is_internationalised?()
85
+ end
86
+
87
+ # Define a JSON object with the supplied name and optional constraints
88
+ # on properties (like hash keys) and property values (like hash values)
89
+ # that the object may contain, in abstract terms.
90
+ #
91
+ # +name+:: The JSON key
92
+ # +options+:: A +Hash+ of options, e.g. :required => true
93
+ # &block:: Optional block declaring the fields making up the nested
94
+ # hash
95
+ #
96
+ # Example 1 - a Hash where keys must be <= 16 characters long and values
97
+ # must match the Hoodoo::Data::Types::Currency type.
98
+ #
99
+ # class CurrencyHash < Hoodoo::Presenters::Base
100
+ # schema do
101
+ # hash :currencies do
102
+ # keys :length => 16 do
103
+ # type :Currency
104
+ # end
105
+ # end
106
+ # end
107
+ # end
108
+ #
109
+ # See Hoodoo::Presenters::Hash#keys for more information and examples.
110
+ #
111
+ # Example 2 - a Hash where keys must be 'one' or 'two', each with a
112
+ # value matching the given schema.
113
+ #
114
+ # class AltCurrencyHash < Hoodoo::Presenters::Base
115
+ # schema do
116
+ # hash :currencies do
117
+ # key :one do
118
+ # type :Currency
119
+ # end
120
+ #
121
+ # key :two do
122
+ # text :title
123
+ # text :description
124
+ # end
125
+ # end
126
+ # end
127
+ # end
128
+ #
129
+ # See Hoodoo::Presenters::Hash#key for more information and examples.
130
+ #
131
+ def hash( name, options = {}, &block )
132
+ hash = property( name, Hoodoo::Presenters::Hash, options, &block )
133
+ internationalised() if hash.is_internationalised?()
134
+ end
135
+
136
+ # Define a JSON integer with the supplied name and options.
137
+ #
138
+ # +name+:: The JSON key
139
+ # +options+:: A +Hash+ of options, e.g. :required => true
140
+ #
141
+ def integer( name, options = {} )
142
+ property( name, Hoodoo::Presenters::Integer, options )
143
+ end
144
+
145
+ # Define a JSON string with the supplied name and options.
146
+ #
147
+ # +name+:: The JSON key
148
+ # +options+:: A +Hash+ of options, e.g. :required => true, :length => 10
149
+ #
150
+ def string( name, options = {} )
151
+ property( name, Hoodoo::Presenters::String, options )
152
+ end
153
+
154
+ # Define a JSON float with the supplied name and options.
155
+ #
156
+ # +name+:: The JSON key
157
+ # +options+:: A +Hash+ of options, e.g. :required => true
158
+ #
159
+ def float( name, options = {} )
160
+ property( name, Hoodoo::Presenters::Float, options )
161
+ end
162
+
163
+ # Define a JSON decimal with the supplied name and options.
164
+ #
165
+ # +name+:: The JSON key
166
+ # +options+:: A +Hash+ of options, e.g. :required => true, :precision => 10
167
+ #
168
+ def decimal( name, options = {} )
169
+ property( name, Hoodoo::Presenters::Decimal, options )
170
+ end
171
+
172
+ # Define a JSON boolean with the supplied name and options.
173
+ #
174
+ # +name+:: The JSON key
175
+ # +options+:: A +Hash+ of options, e.g. :required => true
176
+ #
177
+ def boolean( name, options = {} )
178
+ property( name, Hoodoo::Presenters::Boolean, options )
179
+ end
180
+
181
+ # Define a JSON date with the supplied name and options.
182
+ #
183
+ # +name+:: The JSON key
184
+ # +options+:: A +Hash+ of options, e.g. :required => true
185
+ #
186
+ def date( name, options = {} )
187
+ property( name, Hoodoo::Presenters::Date, options )
188
+ end
189
+
190
+ # Define a JSON datetime with the supplied name and options.
191
+ #
192
+ # +name+:: The JSON key
193
+ # +options+:: A +Hash+ of options, e.g. :required => true
194
+ #
195
+ def datetime( name, options = {} )
196
+ property( name, Hoodoo::Presenters::DateTime, options )
197
+ end
198
+
199
+ # Define a JSON string of unlimited length with the supplied name
200
+ # and options.
201
+ #
202
+ # +name+:: The JSON key
203
+ # +options+:: A +Hash+ of options, e.g. :required => true
204
+ #
205
+ def text( name, options = {} )
206
+ property( name, Hoodoo::Presenters::Text, options )
207
+ end
208
+
209
+ # Define a JSON string which can only have a restricted set of exactly
210
+ # matched values, with the supplied name and options.
211
+ #
212
+ # +name+:: The JSON key
213
+ # +options+:: A +Hash+ of options, e.g. :required => true and mandatory
214
+ # :from => [array-of-allowed-strings-or-symbols]
215
+ #
216
+ def enum( name, options = {} )
217
+ property( name, Hoodoo::Presenters::Enum, options )
218
+ end
219
+
220
+ # Declares that this Type or Resource has a string field of unlimited
221
+ # length that contains comma-separated tag strings.
222
+ #
223
+ # +field_name+:: Name of the field that will hold the tags.
224
+ # +options+:: Optional options hash. See Hoodoo::Presenters::BaseDSL.
225
+ #
226
+ # Example - a Product resource which supports product tagging:
227
+ #
228
+ # class Product < Hoodoo::Presenters::Base
229
+ # schema do
230
+ # internationalised
231
+ #
232
+ # text :name
233
+ # text :description
234
+ # string :sku, :length => 64
235
+ # tags :tags
236
+ # end
237
+ # end
238
+ #
239
+ def tags( field_name, options = nil )
240
+ options ||= {}
241
+ property( field_name, Hoodoo::Presenters::Tags, options )
242
+ end
243
+
244
+ # Declares that this Type or Resource _refers to_ another Resource
245
+ # instance via its UUID. There's no need to declare the presence of the
246
+ # UUID field _for the instance itself_ on all resource definitions as
247
+ # that's implicit; this #uuid method is just for relational information
248
+ # (AKA associations).
249
+ #
250
+ # +field_name+:: Name of the field that will hold the UUID.
251
+ # +options+:: Options hash. See below.
252
+ #
253
+ # In addition to standard options from Hoodoo::Presenters::BaseDSL,
254
+ # extra option keys and values are:
255
+ #
256
+ # +:resource+:: The name of a resource (as a symbol, e.g. +:Product+) that
257
+ # the UUID should refer to. Implementations _may_ use this
258
+ # to validate that the resource, where a UUID is provided,
259
+ # really is for a Product instance and not something else.
260
+ # Optional.
261
+ #
262
+ # Example - a basket item that refers to an integer quantity of some
263
+ # specific Product resource instance:
264
+ #
265
+ # class BasketItem < Hoodoo::Presenters::Base
266
+ # schema do
267
+ # integer :quantity, :required => true
268
+ # uuid :product_id, :resource => :Product
269
+ # end
270
+ # end
271
+ #
272
+ def uuid( field_name, options = nil )
273
+ options ||= {}
274
+ property(field_name, Hoodoo::Presenters::UUID, options)
275
+ end
276
+
277
+ # Declare that a nested type of a given name is included at this point.
278
+ # This is only normally done within an +array+ or +object+ declaration.
279
+ # The fields of the given named type are considered to be defined inline
280
+ # at the point of declaration - essentially, it's macro expansion.
281
+ #
282
+ # +type_info+:: The Hoodoo::Presenters::Base subclass for the Type in
283
+ # question, e.g. +BasketItem+. The deprecated form of this
284
+ # interface takes the name of the type to nest as a symbol,
285
+ # e.g. +:BasketItem+, in which case the Type must be
286
+ # declared within nested modules "Hoodoo::Data::Types".
287
+ #
288
+ # +options+:: Optional options hash. No options currently defined.
289
+ #
290
+ # It doesn't make sense to mark a +type+ 'field' as +:required+ in the
291
+ # options since the declaration just expands to the contents of the
292
+ # referenced type and it is the definition of that type that determines
293
+ # whether or not its various field(s) are optional or required.
294
+ #
295
+ # Example 1 - a basket includes an array of the Type described by class
296
+ # +BasketItem+:
297
+ #
298
+ # class Basket < Hoodoo::Presenters::Base
299
+ # schema do
300
+ # array :items do
301
+ # type BasketItem
302
+ # end
303
+ # end
304
+ # end
305
+ #
306
+ # A fragment of JSON for a basket might look like this:
307
+ #
308
+ # {
309
+ # "items": [
310
+ # {
311
+ # // (First BasketItem's fields)
312
+ # },
313
+ # {
314
+ # // (First BasketItem's fields)
315
+ # },
316
+ # // etc.
317
+ # ]
318
+ # }
319
+ #
320
+ # Example 2 - a basket item refers to a product description by having
321
+ # its fields inline. So suppose we have this:
322
+ #
323
+ # class Product < Hoodoo::Presenters::Base
324
+ # schema do
325
+ # internationalised
326
+ # text :name
327
+ # text :description
328
+ # end
329
+ # end
330
+ #
331
+ # class BasketItem < Hoodoo::Presenters::Base
332
+ # schema do
333
+ # object :product_data do
334
+ # type Product
335
+ # end
336
+ # end
337
+ # end
338
+ #
339
+ # ...then this would be a valid BasketItem fragment of JSON:
340
+ #
341
+ # {
342
+ # "product_data": {
343
+ # "name": "Washing powder",
344
+ # "description": "Washes whiter than white!"
345
+ # }
346
+ # }
347
+ #
348
+ # It is also possible to use this mechanism for inline expansions when
349
+ # you have, say, a Resource defined _entirely_ in terms of something
350
+ # reused elsewhere as a Type. For example, suppose the product/basket
351
+ # information from above included information on a Currency that was
352
+ # used for payment. It might reuse a Type; meanwhile we might have a
353
+ # resource for managing Currencies, defined entirely through that Type:
354
+ #
355
+ # class Currency < Hoodoo::Presenters::Base
356
+ # schema do
357
+ # string :curency_code, :required => true, :length => 8
358
+ # string :symbol, :length => 16
359
+ # integer :multiplier, :default => 100
360
+ # array :qualifiers do
361
+ # string :qualifier, :length => 32
362
+ # end
363
+ # end
364
+ # end
365
+ #
366
+ # resource :Currency do
367
+ # schema do
368
+ # type Currency # Fields are *inline*
369
+ # end
370
+ # end
371
+ #
372
+ # This means that the *Resource* of +Currency+ has exactly the same
373
+ # fields as the *Type* of Currency. The Resource could define other
374
+ # fields too, though this would be risky as the Type might gain
375
+ # same-named fields in future, leading to undefined behaviour. At such a
376
+ # time, a degree of cut-and-paste and removing the +type+ call from the
377
+ # Resource definition would probably be wise.
378
+ #
379
+ def type( type_info, options = nil )
380
+ options ||= {}
381
+
382
+ if type_info.is_a?( Class ) && type_info < Hoodoo::Presenters::Base
383
+ klass = type_info
384
+ else
385
+ begin
386
+ klass = Hoodoo::Data::Types.const_get( type_info )
387
+ rescue
388
+ raise "Hoodoo::Presenters::Base\#type: Unrecognised type name '#{ type_info }'"
389
+ end
390
+ end
391
+
392
+ self.instance_exec( &klass.get_schema_definition() )
393
+ end
394
+
395
+ # Declare that a resource of a given name is included at this point.
396
+ # This is only normally done within the description of the schema for an
397
+ # interface. The fields of the given named resource are considered to be
398
+ # defined inline at the point of declaration - essentially, it's macro
399
+ # expansion.
400
+ #
401
+ # +resource_info+:: The Hoodoo::Presenters::Base subclass for the
402
+ # Resource in question, e.g. +Product+. The deprecated
403
+ # form of this interface takes the name of the type to
404
+ # nest as a symbol, e.g. +:Product+, in which case the
405
+ # Resource must be declared within nested modules
406
+ # "Hoodoo::Data::Types".
407
+ #
408
+ # +options+:: Optional options hash. No options currently defined.
409
+ #
410
+ # Example - an iterface takes an +Outlet+ resource in its create action.
411
+ #
412
+ # class Outlet < Hoodoo::Presenters::Base
413
+ # schema do
414
+ # internationalised
415
+ #
416
+ # text :name
417
+ # uuid :participant_id, :resource => :Participant, :required => true
418
+ # uuid :calculator_id, :resource => :Calculator
419
+ # end
420
+ # end
421
+ #
422
+ # class OutletInterface < Hoodoo::Services::Interface
423
+ # to_create do
424
+ # resource Outlet
425
+ # end
426
+ # end
427
+ #
428
+ # It doesn't make sense to mark a +resource+ 'field' as +:required+ in
429
+ # the options since the declaration just expands to the contents of the
430
+ # referenced resource and it is the definition of that resource that
431
+ # determines whether or not its various field(s) are optional / required.
432
+ # That is, the following two declarations behave identically:
433
+ #
434
+ # resource Outlet
435
+ #
436
+ # resource Outlet, :required => true # Pointless option!
437
+ #
438
+ def resource( resource_info, options = nil )
439
+ options ||= {}
440
+
441
+ if resource_info.is_a?( Class ) && resource_info < Hoodoo::Presenters::Base
442
+ klass = resource_info
443
+ else
444
+ begin
445
+ klass = Hoodoo::Data::Resources.const_get( resource_info )
446
+ rescue
447
+ raise "Hoodoo::Presenters::Base\#resource: Unrecognised resource name '#{ resource_info }'"
448
+ end
449
+ end
450
+
451
+ self.instance_exec( &klass.get_schema_definition() )
452
+ end
453
+
454
+ # Declares that this Type or Resource contains fields which will may
455
+ # carry human-readable data subject to platform interntionalisation
456
+ # rules. A Resource which is internationalised automatically gains a
457
+ # +language+ field (part of the Platform API's Common Fields) used
458
+ # in resource representations. A Type which is internationalised
459
+ # gains nothing until it is cross-referenced by a Resource definion,
460
+ # at which point the cross-referencing resource becomes itself
461
+ # implicitly internationalised (so it "taints" the resource). For
462
+ # cross-referencing, see #type.
463
+ #
464
+ # +options+:: Optional options hash. No options currently defined.
465
+ #
466
+ # Example - a Member resource with internationalised fields such as
467
+ # the member's name:
468
+ #
469
+ # class Member < Hoodoo::Presenters::Base
470
+ # schema do
471
+ #
472
+ # # Say that Member will contain at least one field that holds
473
+ # # human readable data, causing the Member to be subject to
474
+ # # internationalisation rules.
475
+ #
476
+ # internationalised
477
+ #
478
+ # # Declare fields as normal, for example...
479
+ #
480
+ # text :name
481
+ #
482
+ # end
483
+ # end
484
+ #
485
+ def internationalised( options = nil )
486
+ options ||= {}
487
+ @internationalised = true
488
+ end
489
+
490
+ # An enquiry method related to, but not part of the DSL; returns +true+
491
+ # if the schema instance is internationalised, else +false+.
492
+ #
493
+ def is_internationalised?
494
+ !! @internationalised
495
+ end
496
+
497
+ private
498
+
499
+ # Define a JSON property with the supplied name, type and options.
500
+ # Returns the new property instance.
501
+ #
502
+ # +name+:: The JSON key
503
+ # +type+:: A +Class+ for validation
504
+ # +options+:: A +Hash+ of options, e.g. :required => true
505
+ #
506
+ def property( name, type, options = {}, &block )
507
+ name = name.to_s
508
+ inst = type.new( name, options.merge( { :path => @path + [ name ] } ) )
509
+ inst.instance_eval( &block ) if block_given?
510
+
511
+ @properties ||= {}
512
+ @properties[ name ] = inst
513
+
514
+ return inst
515
+ end
516
+
517
+ end
518
+ end
519
+ end