hoodoo 1.0.2

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 (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,49 @@
1
+ ########################################################################
2
+ # File:: slow_writer.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Base class for slow log writers.
6
+ # ----------------------------------------------------------------------
7
+ # 16-Dec-2014 (ADH): Created.
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+ class Logger
12
+
13
+ # Log writer classes are used through the Hoodoo::Logger class.
14
+ #
15
+ # Subclass SlowWriter if you are writing a log data output mechanism which
16
+ # does not respond very quickly. File output might fall into this category
17
+ # depending upon target deployment infrastructure; exporting logs to a
18
+ # remote logging service over the network would certainly qualify.
19
+ #
20
+ # The subclass only needs to implement
21
+ # Hoodoo::Logger::WriterMixin#report.
22
+ #
23
+ # If a slow writer cannot keep up with a high rate of log messages, some
24
+ # may be dropped. A +:warn+ level message is reported automatically for
25
+ # such cases, describing the number of dropped messages, once the slow
26
+ # writer has caught up.
27
+ #
28
+ # *IMPORTANT*: If you use ActiveRecord in a slow writer class, beware that
29
+ # your writer runs in a ruby Thread. Unless you take steps to prevent it,
30
+ # ActiveRecord will implicitly check out a connection which stays with
31
+ # your Thread forever. This steals a connection from the pool. To prevent
32
+ # this issue, you must use the following pattern:
33
+ #
34
+ # def report( log_level, component, code, data )
35
+ # ActiveRecord::Base.connection_pool.with_connection do
36
+ # # ...Any AciveRecord code goes here...
37
+ # end
38
+ # end
39
+ #
40
+ # Code within the +with_connection+ block uses a temporary connection from
41
+ # the pool which is returned once the block has finished processing. Even
42
+ # if exceptions occur within your ActiveRecord code, the connection is
43
+ # still correctly returned to the pool using the above approach.
44
+ #
45
+ class SlowWriter
46
+ include Hoodoo::Logger::WriterMixin
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,52 @@
1
+ ########################################################################
2
+ # File:: writer_mixin.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Common code for fast and slow log writer base classes.
6
+ # ----------------------------------------------------------------------
7
+ # 16-Dec-2014 (ADH): Created.
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+ class Logger
12
+
13
+ # This mixin is used by Hoodoo::Logger::FastWriter and
14
+ # Hoodoo::Logger::SlowWriter. See those two classes for details.
15
+ #
16
+ module WriterMixin
17
+
18
+ # Hoodoo::Logger::FastWriter and Hoodoo::Logger::SlowWriter
19
+ # subclasses implement this method.
20
+ #
21
+ # Write a structured log message. Writers sending data somewhere with no
22
+ # structure support will need to serialize/flatten the message; others
23
+ # should retain data structures like hashes or arrays.
24
+ #
25
+ # The #report method is only invoked if the logging threshold level of
26
+ # the owning logger is set to an equal or lower level. Implementations
27
+ # do not, therefore, need to check this themselves.
28
+ #
29
+ # +log_level+:: Log level as a symbol - one of, from most trivial to most
30
+ # severe, +:debug+, +:info+, +:warn+ or +:error+.
31
+ #
32
+ # +component+:: Component - for example, a resource name for a specific
33
+ # service implementation, 'Middleware' for Hoodoo itself,
34
+ # or some other name you think is useful. String or Symbol.
35
+ #
36
+ # +code+:: Component-defined code. Think of this in a manner similar
37
+ # to platform error codes, appearing after the "."; messages
38
+ # related to the same thing should share the same code. The
39
+ # intent is to produce log data that someone can filter on
40
+ # code to get useful information about that specific aspect
41
+ # of a service implementation's behaviour.
42
+ #
43
+ # +data+:: A Hash containing the level, component and code-dependent
44
+ # payload data to be logged. Converted to a string with
45
+ # +inspect+ for flat output use in an unstructured context.
46
+ #
47
+ def report( log_level, component, code, data )
48
+ raise( 'Subclasses must implement #report' )
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ ########################################################################
2
+ # File:: file_writer.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Write flat log messages to a file.
6
+ # ----------------------------------------------------------------------
7
+ # 16-Dec-2014 (ADH): Created.
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+ class Logger
12
+
13
+ # Writes unstructured messages to a file. Hoodoo::Logger::SlowWriter
14
+ # subclass. See also Hoodoo::Logger.
15
+ #
16
+ class FileWriter < Hoodoo::Logger::SlowWriter
17
+
18
+ include Hoodoo::Logger::FlattenerMixin
19
+
20
+ # Create a file writer instance. Files are written by opening,
21
+ # adding a log message and closing again, to provide reliability.
22
+ # For this reason, this is a Hoodoo::Logger::SlowWriter subclass.
23
+ #
24
+ # If you want faster file access at the expense of immediate updates
25
+ # / reliability due to buffering, open a file externally to create an
26
+ # I/O stream and pass this persistently-open file's stream to an
27
+ # Hoodoo::Logger::StreamWriter class instead.
28
+ #
29
+ # +pathname+:: Full pathname of a file that can be opened in "ab"
30
+ # (append for writing at end-of-file) mode.
31
+ #
32
+ def initialize( pathname )
33
+ @pathname = pathname
34
+ end
35
+
36
+ # See Hoodoo::Logger::WriterMixin#report.
37
+ #
38
+ def report( log_level, component, code, data )
39
+ File.open( @pathname, 'ab' ) do | file |
40
+ file.puts( flatten( log_level, component, code, data ) )
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,64 @@
1
+ ########################################################################
2
+ # File:: log_entries_dot_com_writer.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Write structured log messages logentries.com.
6
+ # ----------------------------------------------------------------------
7
+ # 08-Jan-2015 (ADH): Created.
8
+ ########################################################################
9
+
10
+ require 'json'
11
+
12
+ module Hoodoo
13
+ class Logger
14
+
15
+ begin # Exception handler as 'le' gem inclusion is optional.
16
+ require 'le' # Might raise LoadError; that's allowed.
17
+
18
+ # Writes structured messages to logentries.com via the "le" gem,
19
+ # which uses its own asynchronous worker thread for network data.
20
+ # Thus, a Hoodoo::Logger::FastWriter subclass. See also
21
+ # Hoodoo::Logger.
22
+ #
23
+ class LogEntriesDotComWriter < Hoodoo::Logger::FastWriter
24
+
25
+ # Create a log writer instance.
26
+ #
27
+ # +token+:: Your logentries.com API token.
28
+ #
29
+ def initialize( token )
30
+ @@logger ||= Le.new( token, :ssl => true )
31
+ end
32
+
33
+ # See Hoodoo::Logger::WriterMixin#report.
34
+ #
35
+ def report( log_level, component, code, data )
36
+ method = case log_level
37
+ when :debug, :info, :warn, :error
38
+ log_level
39
+ else
40
+ :unknown
41
+ end
42
+
43
+ message = {
44
+ :level => log_level,
45
+ :component => component,
46
+ :code => code,
47
+ :data => data
48
+ }
49
+
50
+ # This method is only called if the log level set elsewhere
51
+ # is already appropriate; always make sure that the 'LE' class
52
+ # logging level is as low as possible so it doesn't filter any
53
+ # additional messages accidentally.
54
+
55
+ @@logger.level = ::Logger::DEBUG
56
+ @@logger.send( method, ::JSON.generate( message ) )
57
+ end
58
+ end
59
+
60
+ rescue LoadError # From "require 'le'"
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,43 @@
1
+ ########################################################################
2
+ # File:: file_writer.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Write flat log messages to an I/O stream - STDOUT by
6
+ # default.
7
+ # ----------------------------------------------------------------------
8
+ # 16-Dec-2014 (ADH): Created.
9
+ ########################################################################
10
+
11
+ module Hoodoo
12
+ class Logger
13
+
14
+ # Writes unstructured messages to (presumed) fast output streams such as
15
+ # <tt>$stdout</tt>. Hoodoo::Logger::FastWriter subclass. See also
16
+ # Hoodoo::Logger.
17
+ #
18
+ class StreamWriter < Hoodoo::Logger::FastWriter
19
+
20
+ include Hoodoo::Logger::FlattenerMixin
21
+
22
+ # Create a stream writer instance. Although you could initialize this
23
+ # class with a slow output stream, they're expected to be fast (e.g.
24
+ # terminal output) as this is a Hoodoo::Logger::FastWriter subclass.
25
+ #
26
+ # For reliable file writing, use the Hoodoo::Logger::FileWriter class
27
+ # instead.
28
+ #
29
+ # +output_stream+:: Optional I/O stream instance; default is +$stdout+.
30
+ # The instance must provide a +puts+ implementation.
31
+ #
32
+ def initialize( output_stream = $stdout )
33
+ @output_stream = output_stream
34
+ end
35
+
36
+ # See Hoodoo::Logger::WriterMixin#report.
37
+ #
38
+ def report( log_level, component, code, data )
39
+ @output_stream.puts( flatten( log_level, component, code, data ) )
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,33 @@
1
+ ########################################################################
2
+ # File:: middleware.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Include code implementing the Rack service middleware.
6
+ # ----------------------------------------------------------------------
7
+ # 26-Jan-2015 (ADH): Split from top-level inclusion file.
8
+ ########################################################################
9
+
10
+ # Dependencies
11
+
12
+ require 'hoodoo/utilities'
13
+ require 'hoodoo/errors'
14
+ require 'hoodoo/communicators'
15
+ require 'hoodoo/logger'
16
+ require 'hoodoo/discovery'
17
+ require 'hoodoo/client'
18
+ require 'hoodoo/presenters'
19
+
20
+ # Middleware
21
+
22
+ require 'hoodoo/services/middleware/rack_monkey_patch'
23
+ require 'hoodoo/services/middleware/amqp_log_message'
24
+ require 'hoodoo/services/middleware/amqp_log_writer'
25
+ require 'hoodoo/services/middleware/interaction'
26
+ require 'hoodoo/services/middleware/endpoints/inter_resource_remote'
27
+ require 'hoodoo/services/middleware/endpoints/inter_resource_local'
28
+ require 'hoodoo/services/middleware/middleware'
29
+
30
+ require 'hoodoo/services/middleware/exception_reporting/exception_reporting'
31
+ require 'hoodoo/services/middleware/exception_reporting/base_reporter'
32
+ require 'hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter'
33
+ require 'hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter'
@@ -0,0 +1,45 @@
1
+ ########################################################################
2
+ # File:: presenters.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Include the schema based data validation and rendering code.
6
+ # ----------------------------------------------------------------------
7
+ # 26-Jan-2015 (ADH): Split from top-level inclusion file.
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+
12
+ # Module providing a namespace for schema-based data rendering and
13
+ # validation code.
14
+ #
15
+ module Presenters
16
+ end
17
+ end
18
+
19
+ # Dependencies
20
+
21
+ require 'hoodoo/utilities'
22
+
23
+ # Presenters
24
+
25
+ require 'hoodoo/presenters/base'
26
+ require 'hoodoo/presenters/base_dsl'
27
+ require 'hoodoo/presenters/embedding'
28
+
29
+ require 'hoodoo/presenters/types/field'
30
+ require 'hoodoo/presenters/types/object'
31
+ require 'hoodoo/presenters/types/array'
32
+ require 'hoodoo/presenters/types/hash'
33
+ require 'hoodoo/presenters/types/string'
34
+ require 'hoodoo/presenters/types/text'
35
+ require 'hoodoo/presenters/types/enum'
36
+ require 'hoodoo/presenters/types/boolean'
37
+ require 'hoodoo/presenters/types/float'
38
+ require 'hoodoo/presenters/types/integer'
39
+ require 'hoodoo/presenters/types/decimal'
40
+ require 'hoodoo/presenters/types/date'
41
+ require 'hoodoo/presenters/types/date_time'
42
+ require 'hoodoo/presenters/types/tags'
43
+ require 'hoodoo/presenters/types/uuid'
44
+
45
+ require 'hoodoo/presenters/common_resource_fields'
@@ -0,0 +1,281 @@
1
+ ########################################################################
2
+ # File:: base_presenter.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Schema-based data rendering and validation.
6
+ # ----------------------------------------------------------------------
7
+ # 02-Dec-2014 (ADH): Merge of DocumentedPresenter code into
8
+ # Base.
9
+ ########################################################################
10
+
11
+ module Hoodoo
12
+ module Presenters
13
+
14
+ # Base functionality for JSON validation and presenter (rendering) layers.
15
+ # Subclass this to define a schema against which validation of inbound data
16
+ # or rendering of outbound data can be performed. Call #schema in the
17
+ # subclass to declare, via the DSL, the shape of the schema.
18
+ #
19
+ class Base
20
+
21
+ # Define the JSON schema for validation.
22
+ #
23
+ # &block:: Block that makes calls to the DSL defined in
24
+ # Hoodoo::Presenters::BaseDSL in order to define the schema.
25
+ #
26
+ def self.schema( &block )
27
+ @schema = Hoodoo::Presenters::Object.new
28
+ @schema.instance_eval( &block )
29
+ @schema_definition = block
30
+ end
31
+
32
+ # Given some data that should conform to the subclass presenter's schema,
33
+ # render it to go from the input Ruby Hash, to an output Ruby Hash which
34
+ # will include default values - if any - present in the schema and will
35
+ # drop input fields not present in that schema. In essence, this takes
36
+ # data which may have been programatically generated and sanitises it to
37
+ # produce valid, with-defaults guaranteed valid output.
38
+ #
39
+ # Field +kind+ is taken from the class name. If concerned about clashes
40
+ # between resource names and ActiveRecord model names, put your resource
41
+ # classes inside a module for namespacing - for example:
42
+ #
43
+ # module Resources
44
+ # class Product < Hoodoo::Presenters::Base
45
+ # schema do
46
+ # ...
47
+ # end
48
+ # end
49
+ # end
50
+ #
51
+ # Only the class "leaf" name is used to infer the resource kind - in the
52
+ # above case, that's +Product+.
53
+ #
54
+ # Any field with a schema giving a default value will only appear should
55
+ # a value for that field be _omitted_ in the input data. If the data
56
+ # provides, for example, an explicit +nil+ value then a corresponding
57
+ # explicit +nil+ will be rendered, regardless of defaults.
58
+ #
59
+ # For belt-and-braces, unless subsequent profiling shows performance
60
+ # issues, callers should call #validate first to self-check their internal
61
+ # data against the schema prior to rendering. That way, coding errors
62
+ # will be discovered immediately, rather than hidden / obscured by the
63
+ # rendered sanitisation.
64
+ #
65
+ # Since rendering top-level +nil+ is not valid JSON, should +nil+ be
66
+ # provided as input, it'll be treated as an empty hash ("{}") instead.
67
+ #
68
+ # This is quite a low-level call. For a higher level renderer which
69
+ # Hoodoo service resource implementations will probably want to use for
70
+ # returning resource representations in responses, see ::render_in.
71
+ #
72
+ # +data+:: Hash to be represented. Data within this is compared
73
+ # against the schema being called to ensure that correct
74
+ # information is returned and unknown data is ignored.
75
+ #
76
+ # +uuid+:: Unique ID of the resource instance that is to be
77
+ # represented. If nil / omitted, this is assumed to be
78
+ # a rendering of a type or other non-resource like item.
79
+ # Otherwise the field is mandatory.
80
+ #
81
+ # +created_at+:: Date/Time of instance creation. Only required if UUID
82
+ # has been provided. This is a Ruby DateTime instance or
83
+ # similar, _NOT_ a string!
84
+ #
85
+ # +language+:: Optional language. If the type/resource being rendered
86
+ # is internationalised but this is omitted, then a value
87
+ # of "en-nz" is used as a default.
88
+ #
89
+ def self.render( data, uuid = nil, created_at = nil, language = 'en-nz' )
90
+ target = {}
91
+ data = data || {}
92
+
93
+ @schema.render( data, target )
94
+
95
+ # Common fields are added after rendering the data in case there are
96
+ # any same-named field collisions - platform defaults should take
97
+ # precedence, overwriting previous definitions intentionally.
98
+
99
+ unless ( uuid.nil? )
100
+
101
+ raise "Can't render a Resource with a nil 'created_at'" if created_at.nil?
102
+
103
+ # Field "kind" is taken from the class name; this is a class method
104
+ # so "self.name" yields "Hoodoo::Data::Resources::..." or similar.
105
+ # We could just use "split", but that creates an intermediate Array
106
+ # which uses more RAM and is about half the speed (or worse) of the
107
+ # following alternative (it turns out ActiveSupport 4's #demodulize
108
+ # uses much the same approach).
109
+
110
+ name = self.name
111
+ index = ( name.rindex( '::' ) || -2 ) + 2
112
+ kind = name[ index .. -1 ]
113
+
114
+ target.merge!( {
115
+ 'id' => uuid,
116
+ 'kind' => kind,
117
+ 'created_at' => Time.parse( created_at.to_s ).utc.iso8601
118
+ } )
119
+
120
+ target[ 'language' ] = language if self.is_internationalised?()
121
+
122
+ end
123
+
124
+ return target
125
+ end
126
+
127
+ # A higher level version of ::render, typically called from Hoodoo
128
+ # services in their resource implementation code.
129
+ #
130
+ # As with ::render, data is rendered according to the schema of the
131
+ # object the ::render_in message is sent to. Options specify things like
132
+ # UUID and created-at date. Language information for internationalised
133
+ # fields can be given, but if omitted comes from the given request
134
+ # context data.
135
+ #
136
+ # Additional facilites exist over and above ::render - security scoping
137
+ # information in the resource via its +secured_with+ field is made
138
+ # available through options (see below), along with support for embedded
139
+ # or referenced resource information.
140
+ #
141
+ # +context+:: A Hoodoo::Services::Context instance, which is usually the
142
+ # value passed to a service implementation in calls like
143
+ # Hoodoo::Services::Implementation#list or
144
+ # Hoodoo::Services::Implementation#show.
145
+ #
146
+ # +data+:: Hash to be represented. Data within this is compared
147
+ # against the schema being called to ensure that correct
148
+ # information is returned and unknown data is ignored.
149
+ #
150
+ # +options+:: Options hash, see below.
151
+ #
152
+ # The options keys are Symbols, used as follows:
153
+ #
154
+ # +uuid+:: Same as the +uuid+ parameter to ::render, except
155
+ # mandatory.
156
+ #
157
+ # +created_at+:: Same as the +created_at+ parameter to ::render, except
158
+ # mandatory.
159
+ #
160
+ # +language+:: Optional value for resource's +language+ field; taken
161
+ # from the +context+ parameter if omitted.
162
+ #
163
+ # +embeds+:: A Hoodoo::Presenters::Embedding::Embeds instance that
164
+ # contains (fully rendered) resources which are to be
165
+ # embedded in this rendered representation. Optional.
166
+ #
167
+ # +references+:: A Hoodoo::Presenters::Embedding::References instance
168
+ # that contains UUIDs which are to be embedded in this
169
+ # rendered representation as references. Optional.
170
+ #
171
+ # +secured_with+:: An ActiveRecord::Base subclass instance where the
172
+ # model class includes a +secure_with+ declaration. As
173
+ # per documentation for
174
+ # Hoodoo::ActiveRecord::Secure::ClassMethods#secure and
175
+ # Hoodoo::ActiveRecord::Secure::ClassMethods#secure_with,
176
+ # this leads (potentially) to the generation of the
177
+ # +secured_with+ field and object value in the rendered
178
+ # resource data.
179
+ #
180
+ def self.render_in( context, data, options = {} )
181
+ uuid = options[ :uuid ]
182
+ created_at = options[ :created_at ]
183
+ language = options[ :language ] || context.request.locale
184
+ secured_with = options[ :secured_with ]
185
+ embeds = options[ :embeds ]
186
+ references = options[ :references ]
187
+
188
+ target = self.render( data, uuid, created_at, language )
189
+
190
+ if secured_with.is_a?( ::ActiveRecord::Base )
191
+ result_hash = {}
192
+ extra_scope_map = secured_with.class.secured_with()
193
+
194
+ extra_scope_map.each do | model_field_name, key_or_options |
195
+ resource_field = if key_or_options.is_a?( ::Hash )
196
+ next if key_or_options[ :hide_from_resource ] == true
197
+ key_or_options[ :resource_field_name ] || model_field_name
198
+ else
199
+ model_field_name
200
+ end
201
+
202
+ result_hash[ resource_field.to_s ] = secured_with.send( model_field_name )
203
+ end unless extra_scope_map.nil?
204
+
205
+ target[ 'secured_with' ] = result_hash unless result_hash.empty?
206
+ end
207
+
208
+ target[ '_embed' ] = embeds.retrieve() unless embeds.nil?
209
+ target[ '_reference' ] = references.retrieve() unless references.nil?
210
+
211
+ return target
212
+ end
213
+
214
+ # Is the given rendering of a resource valid? Returns an array of
215
+ # Error Primitive types (as hashes); this will be empty if the data
216
+ # given is valid.
217
+ #
218
+ # +data+:: Ruby Hash representation of JSON data that is to be validated
219
+ # against 'this' schema. Keys must be Strings, not Symbols.
220
+ #
221
+ # +as_resource+:: Check Resource common fields - +id+, +kind+,
222
+ # +created_at+ and (for an internationalised resource)
223
+ # +language+. Otherwise, only basic data schema is
224
+ # examined. Optional; default is +false+.
225
+ #
226
+ def self.validate( data, as_resource = false )
227
+ errors = @schema.validate( data )
228
+
229
+ if as_resource
230
+ common_fields = {
231
+ 'id' => data[ :id ],
232
+ 'created_at' => data[ :created_at ],
233
+ 'kind' => data[ :kind ]
234
+ }
235
+
236
+ if self.is_internationalised?
237
+ common_fields[ 'internationalised' ] = data[ 'internationalised' ]
238
+ Hoodoo::Presenters::CommonResourceFields.get_schema.properties[ 'language' ].required = true
239
+ end
240
+
241
+ errors.merge!( Hoodoo::Presenters::CommonResourceFields.validate( data, false ) )
242
+
243
+ Hoodoo::Presenters::CommonResourceFields.get_schema.properties[ 'language' ].required = false
244
+ end
245
+
246
+ return errors
247
+ end
248
+
249
+ # Walk the schema graph and invoke the given block on each field within
250
+ # it, passing the field instances to the block for each call.
251
+ #
252
+ # All fields including the top-level "root" property (which has an empty
253
+ # string for a name) will be passed to the block in order of definition,
254
+ # recursing into nested objects, arrays and so-on as each is encountered.
255
+ #
256
+ def self.walk( &block )
257
+ @schema.walk( &block )
258
+ end
259
+
260
+ # Does this presenter use internationalisation? Returns +true+ if so,
261
+ # else +false+.
262
+ #
263
+ def self.is_internationalised?
264
+ @schema.is_internationalised?
265
+ end
266
+
267
+ # Return the schema graph. See also #get_schema_definition.
268
+ #
269
+ def self.get_schema
270
+ @schema
271
+ end
272
+
273
+ # Read back the block that defined the schema graph. See also
274
+ # #get_schema.
275
+ #
276
+ def self.get_schema_definition
277
+ @schema_definition
278
+ end
279
+ end
280
+ end
281
+ end