jsonapionify 0.0.1.pre
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 +7 -0
- data/.codeclimate.yml +29 -0
- data/.csslintrc +2 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1171 -0
- data/.ruby-version +1 -0
- data/.travis.yml +10 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +34 -0
- data/TODO +13 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/config.ru +15 -0
- data/fixtures/documentation.json +364 -0
- data/jsonapionify.gemspec +50 -0
- data/lib/core_ext/boolean.rb +3 -0
- data/lib/jsonapionify/api/action.rb +211 -0
- data/lib/jsonapionify/api/attribute.rb +67 -0
- data/lib/jsonapionify/api/base/app_builder.rb +33 -0
- data/lib/jsonapionify/api/base/class_methods.rb +73 -0
- data/lib/jsonapionify/api/base/delegation.rb +15 -0
- data/lib/jsonapionify/api/base/doc_helper.rb +47 -0
- data/lib/jsonapionify/api/base/reloader.rb +10 -0
- data/lib/jsonapionify/api/base/resource_definitions.rb +39 -0
- data/lib/jsonapionify/api/base.rb +25 -0
- data/lib/jsonapionify/api/context.rb +14 -0
- data/lib/jsonapionify/api/context_delegate.rb +42 -0
- data/lib/jsonapionify/api/errors.rb +6 -0
- data/lib/jsonapionify/api/errors_object.rb +66 -0
- data/lib/jsonapionify/api/header_options.rb +13 -0
- data/lib/jsonapionify/api/param_options.rb +46 -0
- data/lib/jsonapionify/api/relationship/blocks.rb +41 -0
- data/lib/jsonapionify/api/relationship/many.rb +61 -0
- data/lib/jsonapionify/api/relationship/one.rb +36 -0
- data/lib/jsonapionify/api/relationship.rb +89 -0
- data/lib/jsonapionify/api/resource/builders.rb +81 -0
- data/lib/jsonapionify/api/resource/class_methods.rb +82 -0
- data/lib/jsonapionify/api/resource/defaults/actions.rb +11 -0
- data/lib/jsonapionify/api/resource/defaults/errors.rb +99 -0
- data/lib/jsonapionify/api/resource/defaults/request_contexts.rb +96 -0
- data/lib/jsonapionify/api/resource/defaults/response_contexts.rb +31 -0
- data/lib/jsonapionify/api/resource/defaults.rb +10 -0
- data/lib/jsonapionify/api/resource/definitions/actions.rb +196 -0
- data/lib/jsonapionify/api/resource/definitions/attributes.rb +51 -0
- data/lib/jsonapionify/api/resource/definitions/contexts.rb +16 -0
- data/lib/jsonapionify/api/resource/definitions/helpers.rb +9 -0
- data/lib/jsonapionify/api/resource/definitions/pagination.rb +79 -0
- data/lib/jsonapionify/api/resource/definitions/params.rb +49 -0
- data/lib/jsonapionify/api/resource/definitions/relationships.rb +42 -0
- data/lib/jsonapionify/api/resource/definitions/request_headers.rb +103 -0
- data/lib/jsonapionify/api/resource/definitions/response_headers.rb +22 -0
- data/lib/jsonapionify/api/resource/definitions/scopes.rb +50 -0
- data/lib/jsonapionify/api/resource/definitions/sorting.rb +85 -0
- data/lib/jsonapionify/api/resource/definitions.rb +14 -0
- data/lib/jsonapionify/api/resource/error_handling.rb +108 -0
- data/lib/jsonapionify/api/resource/http.rb +11 -0
- data/lib/jsonapionify/api/resource/includer.rb +4 -0
- data/lib/jsonapionify/api/resource.rb +35 -0
- data/lib/jsonapionify/api/response.rb +47 -0
- data/lib/jsonapionify/api/server/mock_response.rb +37 -0
- data/lib/jsonapionify/api/server/request.rb +78 -0
- data/lib/jsonapionify/api/server.rb +50 -0
- data/lib/jsonapionify/api/test_helper.rb +52 -0
- data/lib/jsonapionify/api.rb +9 -0
- data/lib/jsonapionify/autoload.rb +52 -0
- data/lib/jsonapionify/callbacks.rb +49 -0
- data/lib/jsonapionify/character_range.rb +41 -0
- data/lib/jsonapionify/continuation.rb +26 -0
- data/lib/jsonapionify/documentation/template.erb +487 -0
- data/lib/jsonapionify/documentation.rb +40 -0
- data/lib/jsonapionify/enumerable_observer.rb +91 -0
- data/lib/jsonapionify/indented_string.rb +27 -0
- data/lib/jsonapionify/inherited_attributes.rb +125 -0
- data/lib/jsonapionify/structure/collections/base.rb +104 -0
- data/lib/jsonapionify/structure/collections/errors.rb +7 -0
- data/lib/jsonapionify/structure/collections/included_resources.rb +39 -0
- data/lib/jsonapionify/structure/collections/resource_identifiers.rb +7 -0
- data/lib/jsonapionify/structure/collections/resources.rb +7 -0
- data/lib/jsonapionify/structure/helpers/errors.rb +71 -0
- data/lib/jsonapionify/structure/helpers/inherits_origin.rb +17 -0
- data/lib/jsonapionify/structure/helpers/member_names.rb +37 -0
- data/lib/jsonapionify/structure/helpers/meta_delegate.rb +16 -0
- data/lib/jsonapionify/structure/helpers/object_defaults.rb +123 -0
- data/lib/jsonapionify/structure/helpers/object_setters.rb +21 -0
- data/lib/jsonapionify/structure/helpers/pagination_links.rb +10 -0
- data/lib/jsonapionify/structure/helpers/validations.rb +296 -0
- data/lib/jsonapionify/structure/maps/base.rb +25 -0
- data/lib/jsonapionify/structure/maps/error_links.rb +7 -0
- data/lib/jsonapionify/structure/maps/links.rb +21 -0
- data/lib/jsonapionify/structure/maps/relationship_links.rb +11 -0
- data/lib/jsonapionify/structure/maps/relationships.rb +23 -0
- data/lib/jsonapionify/structure/maps/resource_links.rb +7 -0
- data/lib/jsonapionify/structure/maps/top_level_links.rb +10 -0
- data/lib/jsonapionify/structure/objects/attributes.rb +29 -0
- data/lib/jsonapionify/structure/objects/base.rb +166 -0
- data/lib/jsonapionify/structure/objects/error.rb +16 -0
- data/lib/jsonapionify/structure/objects/included_resource.rb +14 -0
- data/lib/jsonapionify/structure/objects/jsonapi.rb +7 -0
- data/lib/jsonapionify/structure/objects/link.rb +18 -0
- data/lib/jsonapionify/structure/objects/meta.rb +7 -0
- data/lib/jsonapionify/structure/objects/relationship.rb +20 -0
- data/lib/jsonapionify/structure/objects/resource.rb +45 -0
- data/lib/jsonapionify/structure/objects/resource_identifier.rb +40 -0
- data/lib/jsonapionify/structure/objects/source.rb +10 -0
- data/lib/jsonapionify/structure/objects/top_level.rb +105 -0
- data/lib/jsonapionify/structure.rb +27 -0
- data/lib/jsonapionify/types/array_type.rb +32 -0
- data/lib/jsonapionify/types/boolean_type.rb +22 -0
- data/lib/jsonapionify/types/date_string_type.rb +28 -0
- data/lib/jsonapionify/types/float_type.rb +8 -0
- data/lib/jsonapionify/types/integer_type.rb +9 -0
- data/lib/jsonapionify/types/object_type.rb +22 -0
- data/lib/jsonapionify/types/string_type.rb +66 -0
- data/lib/jsonapionify/types/time_string_type.rb +28 -0
- data/lib/jsonapionify/types.rb +49 -0
- data/lib/jsonapionify/unstrict_proc.rb +28 -0
- data/lib/jsonapionify/version.rb +3 -0
- data/lib/jsonapionify.rb +37 -0
- metadata +530 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module JSONAPIonify::Structure
|
|
2
|
+
module Objects
|
|
3
|
+
# ResourceObjects appear in a JSON API document to represent resources.
|
|
4
|
+
class Resource < ResourceIdentifier
|
|
5
|
+
# The `id` member is not required when the resource object originates at the
|
|
6
|
+
# client and represents a new resource to be created on the server.
|
|
7
|
+
must_contain! :id, if: ->(obj) { obj.server? } # an id representing the resource
|
|
8
|
+
|
|
9
|
+
# In addition, a resource object **MAY** contain any of these top-level members:
|
|
10
|
+
may_contain! :attributes, # An AttributesObject representing some of the resource's data.
|
|
11
|
+
:relationships, # A RelationshipsObject describing relationships between the resource and other JSON API resources.
|
|
12
|
+
:links, # A LinksObject containing links related to the resource.
|
|
13
|
+
:meta # A MetaObject containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.
|
|
14
|
+
|
|
15
|
+
implements :attributes, as: Attributes
|
|
16
|
+
implements :relationships, as: Maps::Relationships
|
|
17
|
+
implements :links, as: Maps::Links
|
|
18
|
+
implements :meta, as: Meta
|
|
19
|
+
|
|
20
|
+
# Note: This spec is agnostic about inflection rules, so the value of `type`
|
|
21
|
+
# can be either plural or singular. However, the same value should be used
|
|
22
|
+
# consistently throughout an implementation.
|
|
23
|
+
def attribute_keys
|
|
24
|
+
return [] unless self[:attributes]
|
|
25
|
+
self[:attributes].keys
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def relationship_keys
|
|
29
|
+
return [] unless self[:relationships]
|
|
30
|
+
self[:relationships].keys
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def relates_to?(other)
|
|
34
|
+
relationships = self[:relationships]
|
|
35
|
+
return false unless relationships
|
|
36
|
+
relationships.any? do |_, resource_identifier|
|
|
37
|
+
Array.wrap(resource_identifier[:data]).any? do |rel|
|
|
38
|
+
rel[:id] == other[:id] && rel[:type] == other[:type]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module JSONAPIonify::Structure
|
|
2
|
+
module Objects
|
|
3
|
+
class ResourceIdentifier < Base
|
|
4
|
+
# A resource object **MUST** contain at least the following top-level members:
|
|
5
|
+
must_contain! :id, :type # Describes ResourceObjects that share common attributes and relationships.
|
|
6
|
+
|
|
7
|
+
# Identification
|
|
8
|
+
# ==============
|
|
9
|
+
#
|
|
10
|
+
# The values of the `id` and `type` members **MUST** be strings.
|
|
11
|
+
type_of! :id, must_be: String
|
|
12
|
+
type_of! :type, must_be: String
|
|
13
|
+
|
|
14
|
+
# The values of `type` members **MUST** adhere to the same constraints as member names.
|
|
15
|
+
validate!(:type, message: 'is not a valid member name') do |*, value|
|
|
16
|
+
Helpers::MemberNames.valid? value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
validate_object!(with: :duplicate_does_not_exist?, message: 'is not unique')
|
|
20
|
+
|
|
21
|
+
def duplicate_exists?
|
|
22
|
+
return false unless parent.is_a?(Array)
|
|
23
|
+
peers = parent - [self]
|
|
24
|
+
peers.any? { |peer| same_as? peer }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def duplicate_does_not_exist?
|
|
28
|
+
!duplicate_exists?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def same_as?(other)
|
|
32
|
+
return false unless other.is_a? ResourceIdentifier
|
|
33
|
+
matches_id = other.has_key?(:id) && has_key?(:id) && other[:id] == self[:id]
|
|
34
|
+
matches_type = other[:type] == self[:type]
|
|
35
|
+
matches_type && matches_id
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module JSONAPIonify::Structure
|
|
2
|
+
module Objects
|
|
3
|
+
class Source < Base
|
|
4
|
+
may_contain!(
|
|
5
|
+
:pointer, # a JSON Pointer [[RFC6901](https://tools.ietf.org/html/rfc6901)] to the associated entity in the request document
|
|
6
|
+
:parameter # a string indicating which URI query parameter caused the error.
|
|
7
|
+
)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# TopLevelObject
|
|
2
|
+
# ========
|
|
3
|
+
#
|
|
4
|
+
# A JSON object **MUST** be at the root of every JSON API request and response
|
|
5
|
+
# containing data. This object defines a document's "top level".
|
|
6
|
+
module JSONAPIonify::Structure
|
|
7
|
+
module Objects
|
|
8
|
+
class TopLevel < Base
|
|
9
|
+
attr_reader :origin
|
|
10
|
+
|
|
11
|
+
default(:jsonapi) { Jsonapi.new version: '1.0' }
|
|
12
|
+
|
|
13
|
+
# A document **MUST** contain at least one of:
|
|
14
|
+
must_contain_one_of!(
|
|
15
|
+
# **data:** The document's "primary data"
|
|
16
|
+
:data,
|
|
17
|
+
# **errors:** An array of errors
|
|
18
|
+
:errors,
|
|
19
|
+
# **meta:** a meta object that contains non-standard meta-information.
|
|
20
|
+
:meta
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
collects :errors, as: Collections::Errors
|
|
24
|
+
implements :meta, as: Meta
|
|
25
|
+
|
|
26
|
+
# The members `data` and `errors` **MUST NOT** coexist in the same document.
|
|
27
|
+
must_not_coexist! :data, :errors
|
|
28
|
+
|
|
29
|
+
# A document **MAY** contain any of these top-level members:
|
|
30
|
+
may_contain!(
|
|
31
|
+
# **links:** a links_object related to the primary data.
|
|
32
|
+
:links,
|
|
33
|
+
# **included:** an array of resource objects that are related to the primary.
|
|
34
|
+
:included,
|
|
35
|
+
# **jsonapi:** an object describing the server's implementation.
|
|
36
|
+
:jsonapi
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
implements :links, as: Maps::TopLevelLinks
|
|
40
|
+
collects :included, as: Collections::IncludedResources
|
|
41
|
+
implements :jsonapi, as: Jsonapi
|
|
42
|
+
is_resource = ->(obj) { (obj.keys - %i{id type}).present? }
|
|
43
|
+
collects_or_implements(
|
|
44
|
+
:data,
|
|
45
|
+
collects: Collections::Resources,
|
|
46
|
+
implements: Resource,
|
|
47
|
+
if: ->(obj) {
|
|
48
|
+
obj.is_a?(Resource) || (obj.is_a?(Hash) && is_resource[obj])
|
|
49
|
+
})
|
|
50
|
+
collects_or_implements(
|
|
51
|
+
:data,
|
|
52
|
+
collects: Collections::ResourceIdentifiers,
|
|
53
|
+
implements: ResourceIdentifier,
|
|
54
|
+
if: ->(obj) {
|
|
55
|
+
obj.is_a?(ResourceIdentifier) || (obj.is_a?(Hash) && !is_resource[obj])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
# If a document does not contain a top-level `data` key, the `included` member
|
|
59
|
+
# **MUST NOT** be present either.
|
|
60
|
+
may_not_exist! :included, without: :data
|
|
61
|
+
|
|
62
|
+
# The document's "primary data" is a representation of the resource or collection
|
|
63
|
+
# of resources targeted by a request.
|
|
64
|
+
# Primary data **MUST** be either:
|
|
65
|
+
type_of! :data, must_be: [
|
|
66
|
+
# A single **ResourceObject**
|
|
67
|
+
Resource,
|
|
68
|
+
# A single **ResourceIdentifierObject**
|
|
69
|
+
ResourceIdentifier,
|
|
70
|
+
# Null
|
|
71
|
+
NilClass,
|
|
72
|
+
# A collection of **ResourceObjects**
|
|
73
|
+
Collections::Resources,
|
|
74
|
+
# A collection of **[ResourceIdentifierObjects](resource_identifier_object.html)**
|
|
75
|
+
Collections::ResourceIdentifiers
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
def compile(*)
|
|
79
|
+
compiled = super
|
|
80
|
+
compiled_errors = compiled['errors'] || []
|
|
81
|
+
all_errors = compiled_errors | errors.as_collection.compile
|
|
82
|
+
if all_errors.present?
|
|
83
|
+
self.class.new(
|
|
84
|
+
errors: all_errors,
|
|
85
|
+
meta: {
|
|
86
|
+
invalid_object: to_hash
|
|
87
|
+
}
|
|
88
|
+
).compile
|
|
89
|
+
else
|
|
90
|
+
compiled
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def as(origin)
|
|
95
|
+
copy.tap do |obj|
|
|
96
|
+
obj.instance_variable_set :@origin, origin
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
after_initialize do
|
|
101
|
+
@origin = :server
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module JSONAPIonify
|
|
2
|
+
module Structure
|
|
3
|
+
|
|
4
|
+
ValidationError = Class.new StandardError
|
|
5
|
+
|
|
6
|
+
module Collections
|
|
7
|
+
extend JSONAPIonify::Autoload
|
|
8
|
+
autoload_all 'structure/collections'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Maps
|
|
12
|
+
extend JSONAPIonify::Autoload
|
|
13
|
+
autoload_all 'structure/maps'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module Objects
|
|
17
|
+
include Maps
|
|
18
|
+
extend JSONAPIonify::Autoload
|
|
19
|
+
autoload_all 'structure/objects'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Helpers
|
|
23
|
+
extend JSONAPIonify::Autoload
|
|
24
|
+
autoload_all 'structure/helpers'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module JSONAPIonify::Types
|
|
2
|
+
class ArrayType < BaseType
|
|
3
|
+
|
|
4
|
+
after_initialize do
|
|
5
|
+
unless options[:of].is_a? BaseType
|
|
6
|
+
raise TypeError, "#{options[:of]} is not a valid JSON type."
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def load(value)
|
|
11
|
+
super unless options[:of]
|
|
12
|
+
value.map do |item|
|
|
13
|
+
options[:of].load(item)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def dump(value)
|
|
18
|
+
super unless options[:of]
|
|
19
|
+
value.map do |item|
|
|
20
|
+
options[:of].dump(item)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def sample(field_name)
|
|
25
|
+
field_name = field_name.to_s.singularize.to_sym
|
|
26
|
+
3.times.map do
|
|
27
|
+
(options[:of] || StringType.new).sample(field_name)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module JSONAPIonify::Types
|
|
2
|
+
class BooleanType < BaseType
|
|
3
|
+
|
|
4
|
+
def load(value)
|
|
5
|
+
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def dump(value)
|
|
9
|
+
case value
|
|
10
|
+
when true, false
|
|
11
|
+
value
|
|
12
|
+
else
|
|
13
|
+
raise TypeError, "#{value} is not a valid JSON #{name}."
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def sample(*)
|
|
18
|
+
[true, false].sample
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'faker'
|
|
2
|
+
|
|
3
|
+
module JSONAPIonify::Types
|
|
4
|
+
class DateStringType < BaseType
|
|
5
|
+
def load(value)
|
|
6
|
+
Date.parse value
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def dump(value)
|
|
10
|
+
case value
|
|
11
|
+
when Date
|
|
12
|
+
Oj.dump(value.to_date)
|
|
13
|
+
else
|
|
14
|
+
raise TypeError, "#{value} is not a valid JSON #{name}."
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sample(field_name)
|
|
19
|
+
field_name = field_name.to_s
|
|
20
|
+
if field_name.to_s.end_with?('ed_at') || field_name.include?('start')
|
|
21
|
+
Faker::Date.backward
|
|
22
|
+
elsif field_name.include?('end')
|
|
23
|
+
Faker::Date.forward
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
|
2
|
+
|
|
3
|
+
module JSONAPIonify::Types
|
|
4
|
+
class ObjectType < BaseType
|
|
5
|
+
|
|
6
|
+
def load(value)
|
|
7
|
+
super(value).deep_symbolize_keys
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def dump(value)
|
|
11
|
+
super(value.deep_stringify_keys)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sample(field_name)
|
|
15
|
+
field_name = field_name.to_s.singularize.to_sym
|
|
16
|
+
%i{foo bar baz}.each_with_object({}) do |k, h|
|
|
17
|
+
h[k] = StringType.new.sample(field_name)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'faker'
|
|
2
|
+
|
|
3
|
+
module JSONAPIonify::Types
|
|
4
|
+
class StringType < BaseType
|
|
5
|
+
class StringSampler
|
|
6
|
+
delegate *Faker::Address.methods(false), to: Faker::Address
|
|
7
|
+
delegate *Faker::Code.methods(false), to: Faker::Code
|
|
8
|
+
delegate :suffix, :catch_phrase, :bs, :ein, :duns_number, :logo, to: Faker::Company
|
|
9
|
+
alias_method :slogan, :catch_phrase
|
|
10
|
+
delegate :name, to: Faker::Company, prefix: :company
|
|
11
|
+
alias_method :company, :company_name
|
|
12
|
+
delegate :credit_card, to: Faker::Finance, prefix: :company
|
|
13
|
+
delegate *Faker::Internet.methods(false), to: Faker::Internet
|
|
14
|
+
delegate :first_name, :last_name, :prefix, :suffix, :title, to: Faker::Name
|
|
15
|
+
delegate *Faker::PhoneNumber.methods(false), to: Faker::PhoneNumber
|
|
16
|
+
alias_method :phone, :phone_number
|
|
17
|
+
alias_method :mobile, :cell_phone
|
|
18
|
+
alias_method :cell, :cell_phone
|
|
19
|
+
delegate *Faker::Commerce.methods(false), to: Faker::Commerce
|
|
20
|
+
delegate *Faker::Avatar.methods(false), to: Faker::Avatar, prefix: :avatar
|
|
21
|
+
alias_method :avatar_url, :avatar_image
|
|
22
|
+
alias_method :profile_image, :avatar_image
|
|
23
|
+
alias_method :profile_pic, :avatar_image
|
|
24
|
+
delegate :birthday, to: Faker::Date
|
|
25
|
+
|
|
26
|
+
def initialize(field_name)
|
|
27
|
+
@field_name = field_name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def hacker_speak
|
|
31
|
+
Faker::Hacker.say_something_smart
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def full_name
|
|
35
|
+
Faker::Name.name
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def domain
|
|
39
|
+
[Faker::Internet.domain_word, Faker::Internet.domain_suffix].join '.'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def description
|
|
43
|
+
Faker::Lorem.paragraph
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
alias_method :body, :description
|
|
47
|
+
alias_method :content, :description
|
|
48
|
+
alias_method :prompt, :description
|
|
49
|
+
|
|
50
|
+
def value
|
|
51
|
+
if self.class.instance_methods(false).include?(@field_name)
|
|
52
|
+
public_send(@field_name)
|
|
53
|
+
elsif (field = self.class.instance_methods(false).find { |m| @field_name.to_s.include? m.to_s })
|
|
54
|
+
public_send(field)
|
|
55
|
+
else
|
|
56
|
+
Faker::Lorem.word
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def sample(field_name)
|
|
63
|
+
StringSampler.new(field_name).value
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'faker'
|
|
2
|
+
|
|
3
|
+
module JSONAPIonify::Types
|
|
4
|
+
class TimeStringType < BaseType
|
|
5
|
+
def load(value)
|
|
6
|
+
Time.parse value
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def dump(value)
|
|
10
|
+
case value
|
|
11
|
+
when Time
|
|
12
|
+
JSON.dump(value.to_time)
|
|
13
|
+
else
|
|
14
|
+
raise TypeError, "#{value} is not a valid JSON #{name}."
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sample(field_name)
|
|
19
|
+
field_name = field_name.to_s
|
|
20
|
+
if field_name.to_s.end_with?('ed_at') || field_name.include?('start')
|
|
21
|
+
Faker::Time.backward
|
|
22
|
+
elsif field_name.include?('end')
|
|
23
|
+
Faker::Time.forward
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'oj'
|
|
2
|
+
|
|
3
|
+
module JSONAPIonify::Types
|
|
4
|
+
extend JSONAPIonify::Autoload
|
|
5
|
+
autoload_all
|
|
6
|
+
|
|
7
|
+
def types
|
|
8
|
+
DefinitionFinder
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module DefinitionFinder
|
|
12
|
+
def self.method_missing(m, *args)
|
|
13
|
+
JSONAPIonify::Types.const_get("#{m}Type", false).new(*args)
|
|
14
|
+
rescue NameError
|
|
15
|
+
raise TypeError, "#{m} is not a valid JSON type."
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class BaseType
|
|
20
|
+
include JSONAPIonify::Callbacks
|
|
21
|
+
define_callbacks :initialize
|
|
22
|
+
|
|
23
|
+
def name
|
|
24
|
+
self.class.name.split('::').last.chomp('Type')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attr_reader :options
|
|
28
|
+
|
|
29
|
+
def initialize(**options)
|
|
30
|
+
run_callbacks :initialize do
|
|
31
|
+
@options = options
|
|
32
|
+
end
|
|
33
|
+
freeze
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def load(non_ruby)
|
|
37
|
+
non_ruby
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def dump(ruby)
|
|
41
|
+
JSON.load JSON.dump ruby
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def verify(non_ruby)
|
|
45
|
+
dump(load(non_ruby)) == non_ruby
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module JSONAPIonify
|
|
2
|
+
module UnstrictProc
|
|
3
|
+
refine Proc do
|
|
4
|
+
def unstrict
|
|
5
|
+
return self unless lambda?
|
|
6
|
+
req_count = required_parameters.count
|
|
7
|
+
Proc.new do |*arguments|
|
|
8
|
+
if req_count > arguments.count
|
|
9
|
+
(req_count - arguments.count).times { arguments << nil }
|
|
10
|
+
elsif req_count < arguments.count
|
|
11
|
+
arguments = req_count == 0 ? [] : arguments[0..(req_count - 1)]
|
|
12
|
+
end
|
|
13
|
+
call(*arguments)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def parameters_hash
|
|
20
|
+
parameters.each_with_object({}) { |(k, v), h| (h[k] ||= []) << v }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def required_parameters
|
|
24
|
+
parameters_hash[:req] || []
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/jsonapionify.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'pry' rescue nil
|
|
2
|
+
require 'core_ext/boolean'
|
|
3
|
+
require "active_support/core_ext/string/inflections"
|
|
4
|
+
require "active_support/core_ext/hash/keys"
|
|
5
|
+
require 'active_support/cache'
|
|
6
|
+
require 'jsonapionify/autoload'
|
|
7
|
+
|
|
8
|
+
module JSONAPIonify
|
|
9
|
+
autoload :VERSION, 'jsonapi-objects/version'
|
|
10
|
+
extend JSONAPIonify::Autoload
|
|
11
|
+
autoload_all 'jsonapionify'
|
|
12
|
+
|
|
13
|
+
def self.path
|
|
14
|
+
__dir__
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.parse(hash)
|
|
18
|
+
hash = JSON.parse(hash) if hash.is_a? String
|
|
19
|
+
Structure::Objects::TopLevel.from_hash(hash)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.new_object
|
|
23
|
+
Structure::Objects::TopLevel.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.cache(store, *args)
|
|
27
|
+
self.cache_store = ActiveSupport::Cache.lookup_store(store, *args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.cache_store=(store)
|
|
31
|
+
@cache_store = store
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.cache_store
|
|
35
|
+
@cache_store ||= ActiveSupport::Cache.lookup_store :null_store
|
|
36
|
+
end
|
|
37
|
+
end
|