surrealist 0.1.2 → 0.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cad5fa813b903c8a83c6618f48a8e5f027244346
4
- data.tar.gz: 4c65f03f060c4c93ae2dd036f634bcc84ab77d3e
3
+ metadata.gz: 712012011eaaceb220f8811228de4b07c6e08460
4
+ data.tar.gz: 5ed1ef86483b6dd864a8769359443c7f760e1ae2
5
5
  SHA512:
6
- metadata.gz: 85121fc7dd2a504fe51d03337c52d2ea08784eeca7fbb150f43f047bfe9c915cff1cb813051307cff9a552ad3c564f891eadca1e8dd18e412a850b150f85cd23
7
- data.tar.gz: 140e6ced9ee0c3e35b77417e12279699ab0468d7c154e9f8cf5bf89e2a73f7bb065303dc5a39013153acd1c5ca9aeea0b3dd0b477cdcde64cfd5a7f295061bd5
6
+ metadata.gz: b15fda40fbc90382e61703564c4e7a386c521036b60227e902df8e6fd1216c933d1281ac4dc5305f0b641475ebc83187b61354550a603e086026bc0de94d0330
7
+ data.tar.gz: dc9d2a1a70f6696f5dec95214125b7fe9677ff5c19e6aa9561318127f05b30ea60b0e0dcc694436ac9313879d9fd98e4e23824532ed1f9723534dedc3daa1734
data/CHANGELOG.md CHANGED
@@ -1,11 +1,19 @@
1
+ # 0.1.4
2
+ ## Added
3
+ * Optional `include_root` argument to wrap schema in a root key. [#15](https://github.com/nesaulov/surrealist/pull/15)
4
+ ## Fixed
5
+ * Performance of schema cloning.
6
+ ## Changed
7
+ * `Boolean` module renamed to `Bool`.
8
+
1
9
  # 0.1.2
2
10
  ## Added
3
- * `Any` module for skipping type checks
4
- * Optional `camelize` argument to convert keys to camelBacks
11
+ * `Any` module for skipping type checks.
12
+ * Optional `camelize` argument to convert keys to camelBacks.
5
13
 
6
14
  # 0.1.0
7
15
  ## Fixed
8
- * Fix schema mutability issue
16
+ * Fix schema mutability issue.
9
17
  ## Changed
10
18
  * Change `schema` class method to `json_schema` due to compatibility issues with other gems.
11
19
 
data/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
  [![Inline docs](http://inch-ci.org/github/nesaulov/surrealist.svg?branch=master)](http://inch-ci.org/github/nesaulov/surrealist)
5
5
  [![Gem Version](https://badge.fury.io/rb/surrealist.svg)](https://rubygems.org/gems/surrealist)
6
6
 
7
+ ![Surrealist](surrealist-icon.png)
8
+
7
9
  A gem that provides DSL for serialization of plain old Ruby objects to JSON in a declarative style
8
10
  by defining a `json_schema`. It also provides a trivial type checking in the runtime before serialization.
9
11
  [Yard documentation](http://www.rubydoc.info/github/nesaulov/surrealist/master)
@@ -13,7 +15,7 @@ by defining a `json_schema`. It also provides a trivial type checking in the run
13
15
  A typical use case for this gem could be, for example, serializing a (decorated) object outside
14
16
  of the view context. The schema is described through a hash, so you can build the structure
15
17
  of serialized object independently of its methods and attributes, while also having possibility
16
- to serialize nested objects and structures.
18
+ to serialize nested objects and structures. [Introductory blogpost.](https://medium.com/@billikota/introducing-surrealist-a-gem-to-serialize-ruby-objects-according-to-a-defined-schema-6ca7e550628d)
17
19
 
18
20
  * [Installation](#installation)
19
21
  * [Usage](#usage)
@@ -23,11 +25,14 @@ to serialize nested objects and structures.
23
25
  * [Usage with Dry::Types](#usage-with-drytypes)
24
26
  * [Build schema](#build-schema)
25
27
  * [Camelization](#camelization)
28
+ * [Include root](#include-root)
26
29
  * [Bool and Any](#bool-and-any)
27
30
  * [Type errors](#type-errors)
28
31
  * [Undefined methods in schema](#undefined-methods-in-schema)
29
32
  * [Other notes](#other-notes)
33
+ * [Roadmap](#roadmap)
30
34
  * [Contributing](#contributing)
35
+ * [Credits](#credits)
31
36
  * [License](#license)
32
37
 
33
38
 
@@ -63,17 +68,14 @@ class Person
63
68
  include Surrealist
64
69
 
65
70
  json_schema do
66
- {
67
- foo: String,
68
- bar: Integer,
69
- }
71
+ { name: String, age: Integer }
70
72
  end
71
73
 
72
- def foo
73
- 'This is a string'
74
+ def name
75
+ 'John Doe'
74
76
  end
75
77
 
76
- def bar
78
+ def age
77
79
  42
78
80
  end
79
81
  end
@@ -83,7 +85,7 @@ end
83
85
 
84
86
  ``` ruby
85
87
  Person.new.surrealize
86
- # => '{ "foo": "This is a string", "bar" :42 }'
88
+ # => '{ "name": "John Doe", "age": 42 }'
87
89
  ```
88
90
 
89
91
  ### Nested structures
@@ -140,7 +142,7 @@ class User
140
142
  end
141
143
 
142
144
  User.new.surrealize
143
- # => '{ "name": "John Doe", "credit_card": { "number" :1234, "cvv": 322 } }'
145
+ # => '{ "name": "John Doe", "credit_card": { "number": 1234, "cvv": 322 } }'
144
146
 
145
147
  ```
146
148
 
@@ -149,7 +151,7 @@ You can use `Dry::Types` for type checking. Note that Surrealist does not ship
149
151
  with dry-types by default, so you should do the [installation and configuration](http://dry-rb.org/gems/dry-types/)
150
152
  by yourself. All built-in features of dry-types work, so if you use, say, `Types::Coercible::String`,
151
153
  your data will be coerced if it is able to, otherwise you will get a TypeError.
152
- Assuming, that you have defined module called `Types`:
154
+ Assuming that you have defined module called `Types`:
153
155
 
154
156
  ``` ruby
155
157
  require 'dry-types'
@@ -169,25 +171,25 @@ class Car
169
171
  end
170
172
 
171
173
  def age;
172
- '7';
174
+ '7'
173
175
  end
174
176
 
175
177
  def previous_owner;
176
- 'John Doe';
178
+ 'John Doe'
177
179
  end
178
180
 
179
181
  def horsepower;
180
- 140;
182
+ 140
181
183
  end
182
184
 
183
185
  def brand;
184
- 'Toyota';
186
+ 'Toyota'
185
187
  end
186
188
 
187
189
  def doors; end
188
190
 
189
191
  def fuel_system;
190
- 'Direct injection';
192
+ 'Direct injection'
191
193
  end
192
194
  end
193
195
 
@@ -207,13 +209,54 @@ Car.new.build_schema
207
209
 
208
210
  ### Camelization
209
211
  If you need to have keys in camelBack, you can pass optional `camelize` argument
210
- to `#surrealize`. From the previous example:
212
+ to `#surrealize or #build_schema`. From the previous example:
211
213
 
212
214
  ``` ruby
213
215
  Car.new.surrealize(camelize: true)
214
216
  # => '{ "age": 7, "brand": "Toyota", "doors": null, "horsepower": 140, "fuelSystem": "Direct injection", "previousOwner": "John Doe" }'
215
217
  ```
216
218
 
219
+ ### Include root
220
+ If you want to wrap the resulting JSON into a root key, you can pass optional `include_root` argument
221
+ to `#surrealize` or `#build_schema`. The root key in this case will be taken from the class name of the
222
+ surrealizable object.
223
+ ``` ruby
224
+ class Cat
225
+ include Surrealist
226
+
227
+ json_schema do
228
+ { weight: String }
229
+ end
230
+
231
+ def weight
232
+ '3 kilos'
233
+ end
234
+ end
235
+
236
+ Cat.new.surrealize(include_root: true)
237
+ # => '{ "cat": { "weight": "3 kilos" } }'
238
+ ```
239
+ With nested classes the last namespace will be taken as root key:
240
+ ``` ruby
241
+ class Animal
242
+ class Dog
243
+ include Surrealist
244
+
245
+ json_schema do
246
+ { breed: String }
247
+ end
248
+
249
+ def breed
250
+ 'Collie'
251
+ end
252
+ end
253
+ end
254
+
255
+ Animal::Dog.new.surrealize(include_root: true)
256
+ # => '{ "dog": { "breed": "Collie" } }'
257
+ ```
258
+ Nesting namespaces are [yet to be implemented.](https://github.com/nesaulov/surrealist/issues/14)
259
+
217
260
  ### Bool and Any
218
261
  If you have a parameter that is of boolean type, or if you don't care about the type, you
219
262
  can use `Bool` and `Any` respectively.
@@ -274,14 +317,22 @@ Car.new.surrealize
274
317
  ### Other notes
275
318
  * nil values are allowed by default, so if you have, say, `age: String`, but the actual value is nil,
276
319
  type check will be passed. If you want to be strict about `nil`s consider using `Dry::Types`.
277
- * Surrealist requires ruby of version 2.2 and higher.
320
+ * Surrealist requires MRI ruby of version 2.2 and higher.
278
321
 
279
- ## Contributing
322
+ ## Roadmap
323
+ Here is a list of features that are not implemented yet (contributions are welcome):
324
+ * [ActiveRecord_Relation serialization](https://github.com/nesaulov/surrealist/issues/13)
325
+ * [Collection serialization](https://github.com/nesaulov/surrealist/issues/12)
326
+ * [Delegating serialization to parent class](https://github.com/nesaulov/surrealist/issues/11)
327
+ * [Having nested namespaces being surrealized](https://github.com/nesaulov/surrealist/issues/14)
280
328
 
329
+ ## Contributing
281
330
  Bug reports and pull requests are welcome on GitHub at https://github.com/nesaulov/surrealist.
282
331
  This project is intended to be a safe, welcoming space for collaboration, and contributors are expected
283
332
  to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
284
333
 
285
- ## License
334
+ ## Credits
335
+ The icon was created by [Simon Child from Noun Project](https://thenounproject.com/term/salvador-dali/124566/) and is published under [Creative Commons License](https://creativecommons.org/licenses/by/3.0/us/)
286
336
 
337
+ ## License
287
338
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Surrealist
4
+ # A helper class to camelize, wrap and deeply copy hashes.
5
+ class HashUtils
6
+ class << self
7
+ # Deeply copies the schema hash and wraps it if there is a need to.
8
+ #
9
+ # @param [Object] hash object to be copied.
10
+ # @param [Boolean] include_root optional argument for including root in the hash.
11
+ # @param [Boolean] camelize optional argument for camelizing the root key of the hash.
12
+ # @param [String] klass instance's class name.
13
+ #
14
+ # @return [Object] a copied object
15
+ def deep_copy(hash:, include_root: false, camelize: false, klass: false)
16
+ return copy_hash(hash) unless include_root
17
+ raise_unknown_root! if include_root && !klass
18
+
19
+ actual_class = extract_class(klass)
20
+ root_key = camelize ? camelize(actual_class, false).to_sym : underscore(actual_class).to_sym
21
+ object = Hash[root_key => {}]
22
+ copy_hash(hash, wrapper: object[root_key])
23
+
24
+ object
25
+ end
26
+
27
+ # Converts hash's keys to camelBack keys.
28
+ #
29
+ # @param [Hash] hash a hash to be camelized.
30
+ #
31
+ # @return [Hash] camelized hash.
32
+ def camelize_hash(hash)
33
+ if hash.is_a?(Hash)
34
+ Hash[hash.map { |k, v| [camelize_key(k, false), camelize_hash(v)] }]
35
+ else
36
+ hash
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # Goes through the hash recursively and deeply copies it.
43
+ #
44
+ # @param [Hash] hash the hash to be copied.
45
+ # @param [Hash] wrapper the wrapper of the resulting hash.
46
+ #
47
+ # @return [Hash] deeply copied hash.
48
+ def copy_hash(hash, wrapper: {})
49
+ hash.each_with_object(wrapper) do |(key, value), new|
50
+ new[key] = value.is_a?(Hash) ? copy_hash(value) : value
51
+ end
52
+ end
53
+
54
+ # Converts symbol to string and camelizes it.
55
+ #
56
+ # @param [String | Symbol] key a key to be camelized.
57
+ # @param [Boolean] first_upper should the first letter be capitalized.
58
+ #
59
+ # @return [String | Symbol] camelized key of a hash.
60
+ def camelize_key(key, first_upper = true)
61
+ if key.is_a? Symbol
62
+ camelize(key.to_s, first_upper).to_sym
63
+ elsif key.is_a? String
64
+ camelize(key, first_upper)
65
+ else
66
+ key
67
+ end
68
+ end
69
+
70
+ # Camelizes a string.
71
+ #
72
+ # @param [String] snake_string a string to be camelized.
73
+ # @param [Boolean] first_upper should the first letter be capitalized.
74
+ #
75
+ # @return [String] camelized string.
76
+ def camelize(snake_string, first_upper = true)
77
+ if first_upper
78
+ snake_string.to_s
79
+ .gsub(/(?:^|_)([^_\s]+)/) { Regexp.last_match[1].capitalize }
80
+ else
81
+ parts = snake_string.split('_', 2)
82
+ parts[0] << camelize(parts[1]) if parts.size > 1
83
+ parts[0] || ''
84
+ end
85
+ end
86
+
87
+ # Clones a string and converts first character to lower case.
88
+ #
89
+ # @param [String] string a string to be cloned.
90
+ #
91
+ # @return [String] new string with lower cased first character.
92
+ def uncapitalize(string)
93
+ str = string.dup
94
+ str[0] = str[0].downcase
95
+ str
96
+ end
97
+
98
+ # Converts a string to snake_case.
99
+ #
100
+ # @param [String] string a string to be underscored.
101
+ #
102
+ # @return [String] underscored string.
103
+ def underscore(string)
104
+ string.gsub('::', '_')
105
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
106
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
107
+ .tr('-', '_')
108
+ .downcase
109
+ end
110
+
111
+ # Extract last class from a namespace.
112
+ #
113
+ # @param [String] string full namespace
114
+ #
115
+ # @example Extract class
116
+ # extract_class('Animal::Dog::Collie') # => 'Collie'
117
+ #
118
+ # @return [String] extracted class
119
+ def extract_class(string)
120
+ uncapitalize(string.split('::').last)
121
+ end
122
+
123
+ # Raises Surrealist::UnknownRootError if class's name is unknown.
124
+ #
125
+ # @raise Surrealist::UnknownRootError
126
+ def raise_unknown_root!
127
+ raise Surrealist::UnknownRootError, "Can't wrap schema in root key - class name was not passed"
128
+ end
129
+ end
130
+ end
131
+ end
@@ -4,13 +4,13 @@ module Surrealist
4
4
  # Instance methods that are included to the object's class
5
5
  module InstanceMethods
6
6
  # Invokes +Surrealist+'s class method +surrealize+
7
- def surrealize(camelize: false)
8
- Surrealist.surrealize(self, camelize: camelize)
7
+ def surrealize(camelize: false, include_root: false)
8
+ Surrealist.surrealize(instance: self, camelize: camelize, include_root: include_root)
9
9
  end
10
10
 
11
11
  # Invokes +Surrealist+'s class method +build_schema+
12
- def build_schema(camelize: false)
13
- Surrealist.build_schema(self, camelize: camelize)
12
+ def build_schema(camelize: false, include_root: false)
13
+ Surrealist.build_schema(instance: self, camelize: camelize, include_root: include_root)
14
14
  end
15
15
  end
16
16
  end
@@ -3,6 +3,7 @@
3
3
  module Surrealist
4
4
  # Service class for type checking
5
5
  class TypeHelper
6
+ # Dry-types class matcher
6
7
  DRY_TYPE_CLASS = 'Dry::Types'
7
8
 
8
9
  class << self
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Surrealist
4
4
  # Defines the version of Surrealist
5
- VERSION = '0.1.2'
5
+ VERSION = '0.1.4'
6
6
  end
data/lib/surrealist.rb CHANGED
@@ -4,7 +4,7 @@ require 'surrealist/class_methods'
4
4
  require 'surrealist/instance_methods'
5
5
  require 'surrealist/bool'
6
6
  require 'surrealist/any'
7
- require 'surrealist/utils'
7
+ require 'surrealist/hash_utils'
8
8
  require 'surrealist/type_helper'
9
9
  require 'json'
10
10
 
@@ -22,102 +22,126 @@ module Surrealist
22
22
  # Error class for failed type-checks.
23
23
  class InvalidTypeError < TypeError; end
24
24
 
25
- # @param [Class] base class to include/extend +Surrealist+.
26
- def self.included(base)
27
- base.extend(Surrealist::ClassMethods)
28
- base.include(Surrealist::InstanceMethods)
29
- end
30
-
31
- # Dumps the object's methods corresponding to the schema
32
- # provided in the object's class and type-checks the values.
33
- #
34
- # @param [Object] instance of a class that has +Surrealist+ included.
35
- #
36
- # @return [String] a json-formatted string corresponding to the schema
37
- # provided in the object's class. Values will be taken from the return values
38
- # of appropriate methods from the object.
39
- #
40
- # @raise +Surrealist::UnknownSchemaError+ if no schema was provided in the object's class.
41
- #
42
- # @raise +Surrealist::InvalidTypeError+ if type-check failed at some point.
43
- #
44
- # @raise +Surrealist::UndefinedMethodError+ if a key defined in the schema
45
- # does not have a corresponding method on the object.
46
- #
47
- # @example Define a schema and surrealize the object
48
- # class User
49
- # include Surrealist
50
- #
51
- # json_schema do
52
- # {
53
- # name: String,
54
- # age: Integer,
55
- # }
56
- # end
57
- #
58
- # def name
59
- # 'Nikita'
60
- # end
61
- #
62
- # def age
63
- # 23
64
- # end
65
- # end
66
- #
67
- # User.new.surrealize
68
- # # => "{\"name\":\"Nikita\",\"age\":23}"
69
- # # For more examples see README
70
- def self.surrealize(instance, camelize:)
71
- ::JSON.dump(build_schema(instance, camelize: camelize))
72
- end
25
+ # Error class for undefined root keys for schema wrapping.
26
+ class UnknownRootError < RuntimeError; end
73
27
 
74
- # Builds hash from schema provided in the object's class and type-checks the values.
75
- #
76
- # @param [Object] instance of a class that has +Surrealist+ included.
77
- #
78
- # @return [Hash] a hash corresponding to the schema
79
- # provided in the object's class. Values will be taken from the return values
80
- # of appropriate methods from the object.
81
- #
82
- # @raise +Surrealist::UnknownSchemaError+ if no schema was provided in the object's class.
83
- #
84
- # @raise +Surrealist::InvalidTypeError+ if type-check failed at some point.
85
- #
86
- # @raise +Surrealist::UndefinedMethodError+ if a key defined in the schema
87
- # does not have a corresponding method on the object.
88
- #
89
- # @example Define a schema and surrealize the object
90
- # class User
91
- # include Surrealist
92
- #
93
- # json_schema do
94
- # {
95
- # name: String,
96
- # age: Integer,
97
- # }
98
- # end
99
- #
100
- # def name
101
- # 'Nikita'
102
- # end
103
- #
104
- # def age
105
- # 23
106
- # end
107
- # end
108
- #
109
- # User.new.build_schema
110
- # # => { name: 'Nikita', age: 23 }
111
- # # For more examples see README
112
- def self.build_schema(instance, camelize:)
113
- schema = instance.class.instance_variable_get('@__surrealist_schema')
28
+ class << self
29
+ # @param [Class] base class to include/extend +Surrealist+.
30
+ def included(base)
31
+ base.extend(Surrealist::ClassMethods)
32
+ base.include(Surrealist::InstanceMethods)
33
+ end
114
34
 
115
- if schema.nil?
116
- raise Surrealist::UnknownSchemaError, "Can't serialize #{instance.class} - no schema was provided."
35
+ # Dumps the object's methods corresponding to the schema
36
+ # provided in the object's class and type-checks the values.
37
+ #
38
+ # @param [Object] instance of a class that has +Surrealist+ included.
39
+ # @param [Boolean] camelize optional argument for converting hash to camelBack.
40
+ # @param [Boolean] include_root optional argument for having the root key of the resulting hash
41
+ # as instance's class name.
42
+ #
43
+ # @return [String] a json-formatted string corresponding to the schema
44
+ # provided in the object's class. Values will be taken from the return values
45
+ # of appropriate methods from the object.
46
+ #
47
+ # @raise +Surrealist::UnknownSchemaError+ if no schema was provided in the object's class.
48
+ #
49
+ # @raise +Surrealist::InvalidTypeError+ if type-check failed at some point.
50
+ #
51
+ # @raise +Surrealist::UndefinedMethodError+ if a key defined in the schema
52
+ # does not have a corresponding method on the object.
53
+ #
54
+ # @example Define a schema and surrealize the object
55
+ # class User
56
+ # include Surrealist
57
+ #
58
+ # json_schema do
59
+ # {
60
+ # name: String,
61
+ # age: Integer,
62
+ # }
63
+ # end
64
+ #
65
+ # def name
66
+ # 'Nikita'
67
+ # end
68
+ #
69
+ # def age
70
+ # 23
71
+ # end
72
+ # end
73
+ #
74
+ # User.new.surrealize
75
+ # # => "{\"name\":\"Nikita\",\"age\":23}"
76
+ # # For more examples see README
77
+ def surrealize(instance:, camelize:, include_root:)
78
+ ::JSON.dump(build_schema(instance: instance, camelize: camelize, include_root: include_root))
117
79
  end
118
80
 
119
- hash = Builder.call(schema: Surrealist::Utils.deep_copy(schema), instance: instance)
81
+ # Builds hash from schema provided in the object's class and type-checks the values.
82
+ #
83
+ # @param [Object] instance of a class that has +Surrealist+ included.
84
+ # @param [Boolean] camelize optional argument for converting hash to camelBack.
85
+ # @param [Boolean] include_root optional argument for having the root key of the resulting hash
86
+ # as instance's class name.
87
+ #
88
+ # @return [Hash] a hash corresponding to the schema
89
+ # provided in the object's class. Values will be taken from the return values
90
+ # of appropriate methods from the object.
91
+ #
92
+ # @raise +Surrealist::UnknownSchemaError+ if no schema was provided in the object's class.
93
+ #
94
+ # @raise +Surrealist::InvalidTypeError+ if type-check failed at some point.
95
+ #
96
+ # @raise +Surrealist::UndefinedMethodError+ if a key defined in the schema
97
+ # does not have a corresponding method on the object.
98
+ #
99
+ # @example Define a schema and surrealize the object
100
+ # class User
101
+ # include Surrealist
102
+ #
103
+ # json_schema do
104
+ # {
105
+ # name: String,
106
+ # age: Integer,
107
+ # }
108
+ # end
109
+ #
110
+ # def name
111
+ # 'Nikita'
112
+ # end
113
+ #
114
+ # def age
115
+ # 23
116
+ # end
117
+ # end
118
+ #
119
+ # User.new.build_schema
120
+ # # => { name: 'Nikita', age: 23 }
121
+ # # For more examples see README
122
+ def build_schema(instance:, camelize:, include_root:)
123
+ schema = instance.class.instance_variable_get('@__surrealist_schema')
124
+
125
+ raise_unknown_schema!(instance) if schema.nil?
120
126
 
121
- camelize ? Surrealist::Utils.camelize_hash(hash) : hash
127
+ normalized_schema = Surrealist::HashUtils.deep_copy(
128
+ hash: schema,
129
+ klass: instance.class.name,
130
+ camelize: camelize,
131
+ include_root: include_root,
132
+ )
133
+
134
+ hash = Builder.call(schema: normalized_schema, instance: instance)
135
+ camelize ? Surrealist::HashUtils.camelize_hash(hash) : hash
136
+ end
137
+
138
+ # Raises Surrealist::UnknownSchemaError
139
+ #
140
+ # @param [Object] instance instance of the class without schema defined.
141
+ #
142
+ # @raise Surrealist::UnknownSchemaError
143
+ def raise_unknown_schema!(instance)
144
+ raise Surrealist::UnknownSchemaError, "Can't serialize #{instance.class} - no schema was provided."
145
+ end
122
146
  end
123
147
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: surrealist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nikita Esaulov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-02 00:00:00.000000000 Z
11
+ date: 2017-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -102,11 +102,12 @@ files:
102
102
  - lib/surrealist/bool.rb
103
103
  - lib/surrealist/builder.rb
104
104
  - lib/surrealist/class_methods.rb
105
+ - lib/surrealist/hash_utils.rb
105
106
  - lib/surrealist/instance_methods.rb
106
107
  - lib/surrealist/schema_definer.rb
107
108
  - lib/surrealist/type_helper.rb
108
- - lib/surrealist/utils.rb
109
109
  - lib/surrealist/version.rb
110
+ - surrealist-icon.png
110
111
  - surrealist.gemspec
111
112
  homepage: https://github.com/nesaulov/surrealist
112
113
  licenses:
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Surrealist
4
- # A helper class to camelize hash keys and deep copy objects
5
- class Utils
6
- class << self
7
- # Deep copies the schema hash.
8
- #
9
- # @param [Object] hash object to be copied
10
- #
11
- # @return [Object] a copied object
12
- def deep_copy(hash)
13
- hash.each_with_object({}) do |(key, value), new|
14
- new[key] = value.is_a?(Hash) ? deep_copy(value) : value
15
- end
16
- end
17
-
18
- # Converts hash's keys to camelCase
19
- #
20
- # @param [Hash] hash a hash to be camelized
21
- #
22
- # @return [Hash] camelized hash
23
- def camelize_hash(hash)
24
- if hash.is_a?(Hash)
25
- Hash[hash.map { |k, v| [camelize_key(k, false), camelize_hash(v)] }]
26
- else
27
- hash
28
- end
29
- end
30
-
31
- private
32
-
33
- # Converts symbol to string and camelizes it
34
- #
35
- # @param [String | Symbol] key a key to be camelized
36
- #
37
- # @param [Boolean] first_upper should the first letter be capitalized
38
- #
39
- # @return [String | Symbol] camelized key of a hash
40
- def camelize_key(key, first_upper = true)
41
- if key.is_a? Symbol
42
- camelize(key.to_s, first_upper).to_sym
43
- elsif key.is_a? String
44
- camelize(key, first_upper)
45
- else
46
- key
47
- end
48
- end
49
-
50
- # Camelizes a word
51
- #
52
- # @param [String] snake_word a word to be camelized
53
- #
54
- # @param [Boolean] first_upper should the first letter be capitalized
55
- #
56
- # @return [String] camelized string
57
- def camelize(snake_word, first_upper = true)
58
- if first_upper
59
- snake_word.to_s
60
- .gsub(/(?:^|_)([^_\s]+)/) { Regexp.last_match[1].capitalize }
61
- else
62
- parts = snake_word.split('_', 2)
63
- parts[0] << camelize(parts[1]) if parts.size > 1
64
- parts[0] || ''
65
- end
66
- end
67
- end
68
- end
69
- end