surrealist 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e161583b21b67122b16fc80818d02a053076fb85
4
+ data.tar.gz: fb10c25384a75bbf3b8c68454086dd9d6e145093
5
+ SHA512:
6
+ metadata.gz: 79f775182748e9f4b22b6d88bf05f4fb53f35afa177a85c3290097ab2923df74538e869d7d2b15494e24415da8d08f64de3d21b45b05821148cef8fa9bdeefd1
7
+ data.tar.gz: 0eaa71f001668e89373fc347caa8d1ff70a43a5f780bdedafbc62d39bf344c1e2c9b3c67bf106b0ba6e052bdf988597b59f9f4da7b4f688f63058a8ec50a13fb
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .ruby-version
11
+ TODO.md
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ inherit_gem:
2
+ rubocop-config-umbrellio: lib/rubocop.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.4
6
+
7
+ Style/StringLiterals:
8
+ EnforcedStyle: single_quotes
9
+ ConsistentQuotesInMultiline: true
10
+ Metrics/LineLength:
11
+ Max: 106
12
+ Style/SingleLineMethods:
13
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ before_install: gem install bundler
5
+ script: bundle exec rspec
6
+ rvm:
7
+ - 2.2.5
8
+ - 2.3.1
9
+ - 2.4.0
10
+ - ruby-head
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: ruby-head
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ gem 'coveralls', require: false
7
+ gem 'rubocop-config-umbrellio', require: false
8
+ gem 'yard', require: false unless ENV['TRAVIS']
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Nikita Esaulov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Surrealist
2
+ [![Build Status](https://travis-ci.com/nesaulov/surrealist.svg?token=UM7SJoXQ7Y56NHBpib7v&branch=master)](https://travis-ci.com/nesaulov/surrealist)
3
+ [![Coverage Status](https://coveralls.io/repos/github/nesaulov/surrealist/badge.svg?branch=master)](https://coveralls.io/github/nesaulov/surrealist?branch=master)
4
+
5
+ A gem that provides DSL for serialization of plain old Ruby objects to JSON in a declarative style
6
+ by defining a `schema`. It also provides a trivial type checking in the runtime before serialization.
7
+ [Yard documentation](http://www.rubydoc.info/github/nesaulov/surrealist/master)
8
+
9
+ ## Motivation
10
+ A typical use case for this gem could be, for example, serializing a decorated object outside of the view context.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ``` ruby
17
+ gem 'surrealist'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install surrealist
27
+
28
+
29
+ ## Usage
30
+ Schema should be defined with a block that contains a hash. Every key of the schema should be
31
+ either a name of a method of the surrealizable object (or it's parents/mixins),
32
+ or - in case value is a hash - a symbol: to build nested JSON structures.
33
+ Every value of the hash should be a constant that represents a Ruby class,
34
+ that will be used for type-checks.
35
+
36
+ ### Simple example
37
+ * Include Surrealist in your class.
38
+ * Define a schema with methods that need to be serialized.
39
+ ``` ruby
40
+ class Person
41
+ include Surrealist
42
+
43
+ schema do
44
+ {
45
+ foo: String,
46
+ bar: Integer,
47
+ }
48
+ end
49
+
50
+ def foo
51
+ 'This is a string'
52
+ end
53
+
54
+ def bar
55
+ 42
56
+ end
57
+ end
58
+ ```
59
+ * Surrealize it.
60
+ ``` ruby
61
+ Person.new.surrealize
62
+ # => "{\"foo\":\"This is a string\",\"bar\":42}"
63
+ ```
64
+
65
+ ### Nested structures
66
+ ``` ruby
67
+ class Person
68
+ include Surrealist
69
+
70
+ schema do
71
+ {
72
+ foo: String,
73
+ name: String,
74
+ nested: {
75
+ at: {
76
+ any: Integer,
77
+ level: Boolean,
78
+ },
79
+ },
80
+ }
81
+ end
82
+ # ... method definitions
83
+ end
84
+
85
+ Person.find_by(email: 'example@email.com').surrealize
86
+ # => "{\"foo\":\"Some string\",\"name\":\"John Doe\",\"nested\":{\"at\":{\"any\":42,\"level\":true}}}"
87
+ ```
88
+
89
+ ### Type Errors
90
+ `Surrealist::InvalidTypeError` is thrown if types mismatch.
91
+
92
+ ``` ruby
93
+ class CreditCard
94
+ include Surrealist
95
+
96
+ schema do
97
+ { number: Integer }
98
+ end
99
+
100
+ def number; 'string'; end
101
+ end
102
+
103
+ CreditCard.new.surrealize
104
+ # => Surrealist::InvalidTypeError: Wrong type for key `number`. Expected Integer, got String.
105
+ ```
106
+
107
+ ### Undefined methods in schema
108
+ `Surrealist::UndefinedMethodError` is thrown if a key defined in the schema does not have
109
+ a corresponding method defined in the object.
110
+ ``` ruby
111
+ class Car
112
+ include Surrealist
113
+
114
+ schema do
115
+ { weight: Integer }
116
+ end
117
+ end
118
+
119
+ Car.new.surrealize
120
+ # => Surrealist::UndefinedMethodError: undefined method `weight' for #<Car:0x007f9bc1dc7fa8>. You have probably defined a key in the schema that doesn't have a corresponding method.
121
+ ```
122
+
123
+ ## Contributing
124
+
125
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nesaulov/surrealist.
126
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected
127
+ to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
128
+
129
+ ## License
130
+
131
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'surrealist'
5
+ require 'pry'
6
+
7
+ Pry.start
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Surrealist
4
+ # A class that builds a hash from the schema and type-checks the values.
5
+ class Builder
6
+ # A method that goes recursively through the schema hash, defines the values and type-checks them.
7
+ #
8
+ # @param [Hash] schema the schema defined in the object's class.
9
+ #
10
+ # @param [Object] instance the instance of the object which methods from the schema are called on.
11
+ #
12
+ # @raise +Surrealist::InvalidTypeError+ if type-check failed at some point.
13
+ #
14
+ # @raise +Surrealist::UndefinedMethodError+ if a key defined in the schema
15
+ # does not have a corresponding method on the object.
16
+ #
17
+ # @return [Hash] a hash that will be dumped into JSON.
18
+ def self.call(schema, instance)
19
+ schema.each do |key, value|
20
+ if value.is_a? Hash
21
+ call(value, instance)
22
+ else
23
+ val = instance.send(key)
24
+
25
+ if val.is_a? value
26
+ schema[key] = val
27
+ else
28
+ raise Surrealist::InvalidTypeError,
29
+ "Wrong type for key `#{key}`. Expected #{value}, got #{val.class}."
30
+ end
31
+ end
32
+ end
33
+ rescue NoMethodError => e
34
+ raise Surrealist::UndefinedMethodError,
35
+ "#{e.message}. You have probably defined a key " \
36
+ "in the schema that doesn't have a corresponding method."
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'builder'
4
+ require_relative 'schema_definer'
5
+
6
+ module Surrealist
7
+ # Class methods that are extended by the object.
8
+ module ClassMethods
9
+ # A DSL method to define schema in a declarative style. Schema should be defined with a block
10
+ # that contains a hash.
11
+ # Every key of the schema should be either a name of a method of the
12
+ # surrealizable object (or it's parents/mixins), or - in case value is a hash - a symbol:
13
+ # to build nested JSON structures. Every value of the hash should be a constant that represents
14
+ # a Ruby class, that will be used for type-checks.
15
+ #
16
+ # @param [Proc] _block that contains hash defining the schema
17
+ #
18
+ # @example DSL usage example
19
+ # class User
20
+ # include Surrealist
21
+ #
22
+ # schema do
23
+ # {
24
+ # foo: String,
25
+ # bar: Integer,
26
+ # }
27
+ # end
28
+ #
29
+ # def foo; 'A string'; end
30
+ # def bar; 42; end
31
+ # end
32
+ #
33
+ # User.new.surrealize
34
+ # # => "{\"foo\":\"A string\",\"bar\":42}"
35
+ # # For more examples see README
36
+ #
37
+ # @example Schema with nested structure
38
+ # class Person
39
+ # include Surrealist
40
+ #
41
+ # schema do
42
+ # {
43
+ # foo: String,
44
+ # nested: {
45
+ # bar: Integer,
46
+ # }
47
+ # }
48
+ # end
49
+ #
50
+ # def foo; 'A string'; end
51
+ # def bar; 42; end
52
+ # end
53
+ #
54
+ # Person.new.surrealize
55
+ # # => "{\"foo\":\"A string\",\"nested\":{\"bar\":42}}"
56
+ # # For more examples see README
57
+ def schema(&_block)
58
+ SchemaDefiner.call(self, yield)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A module that is included in +TrueClass+ and +FalseClass+ for boolean type-checks.
4
+ module Boolean; end
5
+ # TrueClass monkey-patch.
6
+ class TrueClass; include Boolean; end
7
+ # FalseClass monkey-patch.
8
+ class FalseClass; include Boolean; end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Surrealist
4
+ # Instance methods that are included to the object's class
5
+ module InstanceMethods
6
+ # Invokes +Surrealist+'s class method +surrealize+
7
+ def surrealize
8
+ Surrealist.surrealize(self)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Surrealist
4
+ # A class that defines a method on the object that stores the schema.
5
+ class SchemaDefiner
6
+ # Defines a method on the object that stores the schema.
7
+ #
8
+ # @param [Object] klass class of the object that needs to be surrealized.
9
+ #
10
+ # @param [Hash] hash the schema defined in the object's class.
11
+ #
12
+ # @return [Method] +__surrealist_schema+ method that stores the schema of the object.
13
+ #
14
+ # @raise +Surrealist::InvalidSchemaError+ if schema was defined not through a hash.
15
+ def self.call(klass, hash)
16
+ raise Surrealist::InvalidSchemaError, 'Schema should be defined as a hash' unless hash.is_a?(Hash)
17
+
18
+ klass.instance_eval do
19
+ define_method '__surrealist_schema' do
20
+ hash
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Surrealist
4
+ # Defines the version of Surrealist
5
+ VERSION = '0.0.4'
6
+ end
data/lib/surrealist.rb ADDED
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'surrealist/class_methods'
4
+ require_relative 'surrealist/instance_methods'
5
+ require_relative 'surrealist/extensions/boolean'
6
+ require 'multi_json'
7
+
8
+ # Main module that provides the +schema+ class method and +surrealize+ instance method.
9
+ module Surrealist
10
+ # Error class for classes without defined +schema+.
11
+ class UnknownSchemaError < RuntimeError; end
12
+
13
+ # Error class for classes with +schema+ defined not as a hash.
14
+ class InvalidSchemaError < RuntimeError; end
15
+
16
+ # Error class for +NoMethodError+.
17
+ class UndefinedMethodError < RuntimeError; end
18
+
19
+ # Error class for failed type-checks.
20
+ class InvalidTypeError < TypeError; end
21
+
22
+ # @param [Class] base class to include/extend +Surrealist+.
23
+ def self.included(base)
24
+ base.extend(Surrealist::ClassMethods)
25
+ base.include(Surrealist::InstanceMethods)
26
+ end
27
+
28
+ # Dumps the object's methods corresponding to the schema
29
+ # provided in the object's class and type-checks the values.
30
+ #
31
+ # @param [Object] instance of a class that has +Surrealist+ included.
32
+ #
33
+ #
34
+ # @return [String] a json-formatted string corresponding to the schema
35
+ # provided in the object's class. Values will be taken from the return values
36
+ # of appropriate methods from the object.
37
+ #
38
+ # @raise +Surrealist::UnknownSchemaError+ if no schema was provided in the object's class.
39
+ #
40
+ # @raise +Surrealist::InvalidTypeError+ if type-check failed at some point.
41
+ #
42
+ # @raise +Surrealist::UndefinedMethodError+ if a key defined in the schema
43
+ # does not have a corresponding method on the object.
44
+ #
45
+ # @example Define a schema and surrealize the object
46
+ # class User
47
+ # include Surrealist
48
+ #
49
+ # schema do
50
+ # {
51
+ # foo: String,
52
+ # bar: Integer,
53
+ # }
54
+ # end
55
+ #
56
+ # def foo; 'A string'; end
57
+ # def bar; 42; end
58
+ # end
59
+ #
60
+ # User.new.surrealize
61
+ # # => "{\"foo\":\"A string\",\"bar\":42}"
62
+ # # For more examples see README
63
+ def self.surrealize(instance)
64
+ schema = instance.__surrealist_schema rescue nil
65
+
66
+ if schema.nil?
67
+ raise Surrealist::UnknownSchemaError, "Can't serialize #{instance.class} - no schema was provided."
68
+ end
69
+
70
+ ::MultiJson.dump(Builder.call(schema, instance))
71
+ end
72
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'surrealist/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'surrealist'
9
+ spec.version = Surrealist::VERSION
10
+ spec.authors = ['Nikita Esaulov']
11
+ spec.email = ['billikota@gmail.com']
12
+
13
+ spec.summary = 'A gem that provides DSL for serialization of plain old Ruby objects to JSON ' \
14
+ 'in a declarative style.'
15
+ spec.description = 'A gem that provides DSL for serialization of plain old Ruby objects to JSON ' \
16
+ 'in a declarative style by defining a `schema`. ' \
17
+ 'It also provides a trivial type checking in the runtime before serialization.'
18
+ spec.homepage = 'https://github.com/nesaulov/surrealist'
19
+ spec.license = 'MIT'
20
+
21
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.bindir = 'exe'
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.11'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'pry'
29
+ spec.add_development_dependency 'rspec', '~> 3.6.0'
30
+
31
+ spec.add_runtime_dependency 'multi_json', '~> 1.0'
32
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: surrealist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Nikita Esaulov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-09-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.6.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.6.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: multi_json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ description: A gem that provides DSL for serialization of plain old Ruby objects to
84
+ JSON in a declarative style by defining a `schema`. It also provides a trivial type
85
+ checking in the runtime before serialization.
86
+ email:
87
+ - billikota@gmail.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - ".rubocop.yml"
95
+ - ".travis.yml"
96
+ - Gemfile
97
+ - LICENSE.txt
98
+ - README.md
99
+ - bin/console
100
+ - lib/surrealist.rb
101
+ - lib/surrealist/builder.rb
102
+ - lib/surrealist/class_methods.rb
103
+ - lib/surrealist/extensions/boolean.rb
104
+ - lib/surrealist/instance_methods.rb
105
+ - lib/surrealist/schema_definer.rb
106
+ - lib/surrealist/version.rb
107
+ - surrealist.gemspec
108
+ homepage: https://github.com/nesaulov/surrealist
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.6.13
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: A gem that provides DSL for serialization of plain old Ruby objects to JSON
132
+ in a declarative style.
133
+ test_files: []