jsonapionify 0.0.1.pre

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