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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +29 -0
  3. data/.csslintrc +2 -0
  4. data/.gitignore +11 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +1171 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +10 -0
  9. data/CODE_OF_CONDUCT.md +13 -0
  10. data/Gemfile +4 -0
  11. data/Guardfile +14 -0
  12. data/LICENSE.txt +21 -0
  13. data/README.md +43 -0
  14. data/Rakefile +34 -0
  15. data/TODO +13 -0
  16. data/bin/console +14 -0
  17. data/bin/setup +7 -0
  18. data/config.ru +15 -0
  19. data/fixtures/documentation.json +364 -0
  20. data/jsonapionify.gemspec +50 -0
  21. data/lib/core_ext/boolean.rb +3 -0
  22. data/lib/jsonapionify/api/action.rb +211 -0
  23. data/lib/jsonapionify/api/attribute.rb +67 -0
  24. data/lib/jsonapionify/api/base/app_builder.rb +33 -0
  25. data/lib/jsonapionify/api/base/class_methods.rb +73 -0
  26. data/lib/jsonapionify/api/base/delegation.rb +15 -0
  27. data/lib/jsonapionify/api/base/doc_helper.rb +47 -0
  28. data/lib/jsonapionify/api/base/reloader.rb +10 -0
  29. data/lib/jsonapionify/api/base/resource_definitions.rb +39 -0
  30. data/lib/jsonapionify/api/base.rb +25 -0
  31. data/lib/jsonapionify/api/context.rb +14 -0
  32. data/lib/jsonapionify/api/context_delegate.rb +42 -0
  33. data/lib/jsonapionify/api/errors.rb +6 -0
  34. data/lib/jsonapionify/api/errors_object.rb +66 -0
  35. data/lib/jsonapionify/api/header_options.rb +13 -0
  36. data/lib/jsonapionify/api/param_options.rb +46 -0
  37. data/lib/jsonapionify/api/relationship/blocks.rb +41 -0
  38. data/lib/jsonapionify/api/relationship/many.rb +61 -0
  39. data/lib/jsonapionify/api/relationship/one.rb +36 -0
  40. data/lib/jsonapionify/api/relationship.rb +89 -0
  41. data/lib/jsonapionify/api/resource/builders.rb +81 -0
  42. data/lib/jsonapionify/api/resource/class_methods.rb +82 -0
  43. data/lib/jsonapionify/api/resource/defaults/actions.rb +11 -0
  44. data/lib/jsonapionify/api/resource/defaults/errors.rb +99 -0
  45. data/lib/jsonapionify/api/resource/defaults/request_contexts.rb +96 -0
  46. data/lib/jsonapionify/api/resource/defaults/response_contexts.rb +31 -0
  47. data/lib/jsonapionify/api/resource/defaults.rb +10 -0
  48. data/lib/jsonapionify/api/resource/definitions/actions.rb +196 -0
  49. data/lib/jsonapionify/api/resource/definitions/attributes.rb +51 -0
  50. data/lib/jsonapionify/api/resource/definitions/contexts.rb +16 -0
  51. data/lib/jsonapionify/api/resource/definitions/helpers.rb +9 -0
  52. data/lib/jsonapionify/api/resource/definitions/pagination.rb +79 -0
  53. data/lib/jsonapionify/api/resource/definitions/params.rb +49 -0
  54. data/lib/jsonapionify/api/resource/definitions/relationships.rb +42 -0
  55. data/lib/jsonapionify/api/resource/definitions/request_headers.rb +103 -0
  56. data/lib/jsonapionify/api/resource/definitions/response_headers.rb +22 -0
  57. data/lib/jsonapionify/api/resource/definitions/scopes.rb +50 -0
  58. data/lib/jsonapionify/api/resource/definitions/sorting.rb +85 -0
  59. data/lib/jsonapionify/api/resource/definitions.rb +14 -0
  60. data/lib/jsonapionify/api/resource/error_handling.rb +108 -0
  61. data/lib/jsonapionify/api/resource/http.rb +11 -0
  62. data/lib/jsonapionify/api/resource/includer.rb +4 -0
  63. data/lib/jsonapionify/api/resource.rb +35 -0
  64. data/lib/jsonapionify/api/response.rb +47 -0
  65. data/lib/jsonapionify/api/server/mock_response.rb +37 -0
  66. data/lib/jsonapionify/api/server/request.rb +78 -0
  67. data/lib/jsonapionify/api/server.rb +50 -0
  68. data/lib/jsonapionify/api/test_helper.rb +52 -0
  69. data/lib/jsonapionify/api.rb +9 -0
  70. data/lib/jsonapionify/autoload.rb +52 -0
  71. data/lib/jsonapionify/callbacks.rb +49 -0
  72. data/lib/jsonapionify/character_range.rb +41 -0
  73. data/lib/jsonapionify/continuation.rb +26 -0
  74. data/lib/jsonapionify/documentation/template.erb +487 -0
  75. data/lib/jsonapionify/documentation.rb +40 -0
  76. data/lib/jsonapionify/enumerable_observer.rb +91 -0
  77. data/lib/jsonapionify/indented_string.rb +27 -0
  78. data/lib/jsonapionify/inherited_attributes.rb +125 -0
  79. data/lib/jsonapionify/structure/collections/base.rb +104 -0
  80. data/lib/jsonapionify/structure/collections/errors.rb +7 -0
  81. data/lib/jsonapionify/structure/collections/included_resources.rb +39 -0
  82. data/lib/jsonapionify/structure/collections/resource_identifiers.rb +7 -0
  83. data/lib/jsonapionify/structure/collections/resources.rb +7 -0
  84. data/lib/jsonapionify/structure/helpers/errors.rb +71 -0
  85. data/lib/jsonapionify/structure/helpers/inherits_origin.rb +17 -0
  86. data/lib/jsonapionify/structure/helpers/member_names.rb +37 -0
  87. data/lib/jsonapionify/structure/helpers/meta_delegate.rb +16 -0
  88. data/lib/jsonapionify/structure/helpers/object_defaults.rb +123 -0
  89. data/lib/jsonapionify/structure/helpers/object_setters.rb +21 -0
  90. data/lib/jsonapionify/structure/helpers/pagination_links.rb +10 -0
  91. data/lib/jsonapionify/structure/helpers/validations.rb +296 -0
  92. data/lib/jsonapionify/structure/maps/base.rb +25 -0
  93. data/lib/jsonapionify/structure/maps/error_links.rb +7 -0
  94. data/lib/jsonapionify/structure/maps/links.rb +21 -0
  95. data/lib/jsonapionify/structure/maps/relationship_links.rb +11 -0
  96. data/lib/jsonapionify/structure/maps/relationships.rb +23 -0
  97. data/lib/jsonapionify/structure/maps/resource_links.rb +7 -0
  98. data/lib/jsonapionify/structure/maps/top_level_links.rb +10 -0
  99. data/lib/jsonapionify/structure/objects/attributes.rb +29 -0
  100. data/lib/jsonapionify/structure/objects/base.rb +166 -0
  101. data/lib/jsonapionify/structure/objects/error.rb +16 -0
  102. data/lib/jsonapionify/structure/objects/included_resource.rb +14 -0
  103. data/lib/jsonapionify/structure/objects/jsonapi.rb +7 -0
  104. data/lib/jsonapionify/structure/objects/link.rb +18 -0
  105. data/lib/jsonapionify/structure/objects/meta.rb +7 -0
  106. data/lib/jsonapionify/structure/objects/relationship.rb +20 -0
  107. data/lib/jsonapionify/structure/objects/resource.rb +45 -0
  108. data/lib/jsonapionify/structure/objects/resource_identifier.rb +40 -0
  109. data/lib/jsonapionify/structure/objects/source.rb +10 -0
  110. data/lib/jsonapionify/structure/objects/top_level.rb +105 -0
  111. data/lib/jsonapionify/structure.rb +27 -0
  112. data/lib/jsonapionify/types/array_type.rb +32 -0
  113. data/lib/jsonapionify/types/boolean_type.rb +22 -0
  114. data/lib/jsonapionify/types/date_string_type.rb +28 -0
  115. data/lib/jsonapionify/types/float_type.rb +8 -0
  116. data/lib/jsonapionify/types/integer_type.rb +9 -0
  117. data/lib/jsonapionify/types/object_type.rb +22 -0
  118. data/lib/jsonapionify/types/string_type.rb +66 -0
  119. data/lib/jsonapionify/types/time_string_type.rb +28 -0
  120. data/lib/jsonapionify/types.rb +49 -0
  121. data/lib/jsonapionify/unstrict_proc.rb +28 -0
  122. data/lib/jsonapionify/version.rb +3 -0
  123. data/lib/jsonapionify.rb +37 -0
  124. 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,8 @@
1
+ module JSONAPIonify::Types
2
+ class FloatType < BaseType
3
+
4
+ def sample(*)
5
+ rand(0.0..201.42).round(2)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module JSONAPIonify::Types
2
+ class IntegerType < BaseType
3
+
4
+ def sample(*)
5
+ rand(1..123)
6
+ end
7
+
8
+ end
9
+ 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
@@ -0,0 +1,3 @@
1
+ module JSONAPIonify
2
+ VERSION = "0.0.1.pre"
3
+ end
@@ -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