surrealist 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: []