representable 3.0.4 → 3.2.0
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 +5 -5
- data/.github/workflows/ci.yml +23 -0
- data/CHANGES.md +14 -0
- data/Gemfile +4 -7
- data/LICENSE +1 -1
- data/README.md +12 -12
- data/Rakefile +1 -6
- data/lib/representable/binding.rb +32 -12
- data/lib/representable/cached.rb +1 -1
- data/lib/representable/coercion.rb +8 -6
- data/lib/representable/config.rb +8 -3
- data/lib/representable/debug.rb +23 -15
- data/lib/representable/declarative.rb +8 -3
- data/lib/representable/decorator.rb +1 -1
- data/lib/representable/definition.rb +7 -2
- data/lib/representable/deserializer.rb +4 -3
- data/lib/representable/for_collection.rb +1 -1
- data/lib/representable/hash/allow_symbols.rb +9 -11
- data/lib/representable/hash/binding.rb +1 -0
- data/lib/representable/hash/collection.rb +4 -2
- data/lib/representable/hash.rb +6 -2
- data/lib/representable/hash_methods.rb +3 -2
- data/lib/representable/insert.rb +1 -1
- data/lib/representable/json/collection.rb +3 -0
- data/lib/representable/json/hash.rb +1 -0
- data/lib/representable/json.rb +5 -7
- data/lib/representable/object/binding.rb +5 -1
- data/lib/representable/object.rb +1 -1
- data/lib/representable/option.rb +19 -0
- data/lib/representable/pipeline.rb +3 -2
- data/lib/representable/pipeline_factories.rb +4 -2
- data/lib/representable/populator.rb +1 -1
- data/lib/representable/represent.rb +1 -0
- data/lib/representable/serializer.rb +2 -1
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml/binding.rb +5 -6
- data/lib/representable/xml.rb +7 -10
- data/lib/representable/yaml/binding.rb +1 -0
- data/lib/representable/yaml.rb +3 -3
- data/lib/representable.rb +18 -25
- data/representable.gemspec +3 -3
- data/test/as_test.rb +4 -4
- data/test/binding_test.rb +10 -10
- data/test/cached_test.rb +19 -19
- data/test/class_test.rb +7 -7
- data/test/coercion_test.rb +33 -22
- data/test/config/inherit_test.rb +14 -14
- data/test/config_test.rb +18 -18
- data/test/decorator_scope_test.rb +3 -3
- data/test/decorator_test.rb +17 -17
- data/test/default_test.rb +7 -7
- data/test/definition_test.rb +32 -32
- data/test/{example.rb → examples/example.rb} +0 -0
- data/test/exec_context_test.rb +6 -6
- data/test/features_test.rb +3 -3
- data/test/filter_test.rb +6 -6
- data/test/for_collection_test.rb +2 -2
- data/test/generic_test.rb +3 -3
- data/test/getter_setter_test.rb +5 -5
- data/test/hash_test.rb +19 -19
- data/test/heritage_test.rb +4 -4
- data/test/if_test.rb +6 -6
- data/test/include_exclude_test.rb +12 -12
- data/test/inherit_test.rb +15 -15
- data/test/inline_test.rb +11 -11
- data/test/instance_test.rb +29 -29
- data/test/is_representable_test.rb +10 -10
- data/test/json_test.rb +7 -7
- data/test/lonely_test.rb +16 -16
- data/test/nested_test.rb +7 -7
- data/test/object_test.rb +7 -7
- data/test/option_test.rb +36 -0
- data/test/parse_pipeline_test.rb +3 -3
- data/test/pipeline_test.rb +43 -43
- data/test/populator_test.rb +15 -15
- data/test/prepare_test.rb +2 -2
- data/test/private_options_test.rb +2 -2
- data/test/reader_writer_test.rb +2 -2
- data/test/render_nil_test.rb +2 -2
- data/test/represent_test.rb +4 -4
- data/test/representable_test.rb +27 -27
- data/test/schema_test.rb +5 -5
- data/test/serialize_deserialize_test.rb +2 -2
- data/test/skip_test.rb +10 -10
- data/test/stringify_hash_test.rb +3 -3
- data/test/test_helper.rb +4 -2
- data/test/uncategorized_test.rb +10 -10
- data/test/user_options_test.rb +4 -4
- data/test/wrap_test.rb +11 -11
- data/test/xml_namespace_test.rb +1 -1
- data/test/xml_test.rb +6 -6
- data/test/yaml_test.rb +20 -20
- metadata +16 -11
- data/.travis.yml +0 -16
- data/lib/representable/autoload.rb +0 -14
- data/test/mongoid_test.rb +0 -31
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f3a1388b7570e31d62c555a87d6165793e9d095cf1bed18c04cb8cbe86bc2ba2
|
|
4
|
+
data.tar.gz: 43e418db52478d3d4fc33f505ce86d840fcb666a8abc83e20269bbfab4c53a3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 39e957975d24f76894ef9a7186fff69155525e5f777c120a77e2ecee8a7dcdccee62b2140ed8ab34ebc9de916a9098d9da846e0befda2c90fa32e4a9ff470ecc
|
|
7
|
+
data.tar.gz: cf309756f2470854283c09bbca25b3200b26ba1702b75e533573382dabd2f33a6f3eeaee963c2cc2bb0ddb9d3bdf026bf7dacba6da3f22f44dc805bc8d1ca505
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
pull_request:
|
|
7
|
+
branches:
|
|
8
|
+
- master
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
ruby: [2.5, 2.6, 2.7, '3.0', "3.1"]
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v2
|
|
19
|
+
- uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: ${{ matrix.ruby }}
|
|
22
|
+
bundler-cache: true
|
|
23
|
+
- run: bundle exec rake
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# 3.2.0
|
|
2
|
+
* Drop support for Virtus Coercion
|
|
3
|
+
* Fix deprecation warning with Nokogiri 1.13.0
|
|
4
|
+
|
|
5
|
+
# 3.1.1
|
|
6
|
+
|
|
7
|
+
* Upgrade `trailblazer-option` to `0.1.1` which supports passing an empty `keyword_arguments`.
|
|
8
|
+
|
|
9
|
+
# 3.1.0
|
|
10
|
+
* Remove circular require
|
|
11
|
+
* Use Dry-types 1.0.0+ as coercion library
|
|
12
|
+
* Renamed Coercion to VirtusCoercion to support old codebases
|
|
13
|
+
* Replace `declarative-option` with [`trailblazer-option`](https://github.com/trailblazer/trailblazer-option)
|
|
14
|
+
|
|
1
15
|
# 3.0.4
|
|
2
16
|
|
|
3
17
|
* Add proper XML namespace support.
|
data/Gemfile
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
source
|
|
1
|
+
source "https://rubygems.org"
|
|
2
2
|
|
|
3
3
|
gemspec
|
|
4
4
|
|
|
5
5
|
group :test do
|
|
6
|
-
gem 'nokogiri', '~> 1.6.8', require: false
|
|
7
|
-
gem "multi_json", require: false
|
|
8
6
|
gem "minitest-line"
|
|
7
|
+
gem "multi_json", require: false
|
|
8
|
+
gem "nokogiri", require: false
|
|
9
9
|
end
|
|
10
|
+
gem 'pry-byebug'
|
|
10
11
|
|
|
11
|
-
# gem "declarative", path: "../declarative"
|
|
12
|
-
# gem "declarative", github: "apotonick/declarative"
|
|
13
|
-
|
|
14
|
-
# gem "uber","0.0.15" #, path: "../uber"
|
data/LICENSE
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2011 -
|
|
1
|
+
Copyright (c) 2011 - 2021 Nick Sutterer and the roar contributors
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
4
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
|
@@ -2,20 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Representable maps Ruby objects to documents and back.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[](https://travis-ci.org/trailblazer/representable)
|
|
5
|
+

|
|
9
7
|
[](http://badge.fury.io/rb/representable)
|
|
10
8
|
|
|
9
|
+
|
|
11
10
|
In other words: Take an object and decorate it with a representer module. This will allow you to render a JSON, XML or YAML document from that object. But that's only half of it! You can also use representers to parse a document and create or populate an object.
|
|
12
11
|
|
|
13
|
-
Representable is helpful for all kind of mappings, rendering and parsing workflows. However, it is mostly useful in API code. Are you planning to write a real REST API with representable? Then check out the [Roar](
|
|
12
|
+
Representable is helpful for all kind of mappings, rendering and parsing workflows. However, it is mostly useful in API code. Are you planning to write a real REST API with representable? Then check out the [Roar](https://github.com/trailblazer/roar) gem first, save work and time and make the world a better place instead.
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
## Full Documentation
|
|
17
16
|
|
|
18
|
-
Representable comes with a rich set of options and semantics for parsing and rendering documents. Its [full documentation](
|
|
17
|
+
Representable comes with a rich set of options and semantics for parsing and rendering documents. Its [full documentation](https://trailblazer.to/2.1/docs/representable.html) can be found on the Trailblazer site.
|
|
19
18
|
|
|
20
19
|
## Example
|
|
21
20
|
|
|
@@ -64,7 +63,7 @@ song = SongRepresenter.new(song).from_json(%{ {"title":"Roxanne"} })
|
|
|
64
63
|
#=> #<Song title="Roxanne", track=nil>
|
|
65
64
|
```
|
|
66
65
|
|
|
67
|
-
Note that parsing hashes per default does [require string keys](
|
|
66
|
+
Note that parsing hashes per default does [require string keys](https://trailblazer.to/2.1/docs/representable.html#representable-api-symbol-keys) and does _not_ pick up symbol keys.
|
|
68
67
|
|
|
69
68
|
|
|
70
69
|
## Collections
|
|
@@ -130,19 +129,20 @@ class AlbumRepresenter < Representable::Decorator
|
|
|
130
129
|
property :track
|
|
131
130
|
collection :composers
|
|
132
131
|
end
|
|
132
|
+
end
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
## More
|
|
136
136
|
|
|
137
137
|
Representable has many more features and can literally parse and render any kind of document to an arbitrary Ruby object graph.
|
|
138
138
|
|
|
139
|
-
Please check the [official documentation for more](
|
|
139
|
+
Please check the [official documentation for more](https://trailblazer.to/2.1/docs/representable.html#representable-api).
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
## Installation
|
|
143
143
|
|
|
144
|
-
The representable gem runs with all Ruby versions >=
|
|
145
|
-
|
|
144
|
+
The representable gem runs with all Ruby versions >= 2.4.0.
|
|
145
|
+
t
|
|
146
146
|
```ruby
|
|
147
147
|
gem 'representable'
|
|
148
148
|
```
|
|
@@ -168,7 +168,7 @@ gem 'nokogiri'
|
|
|
168
168
|
|
|
169
169
|
Representable started as a heavily simplified fork of the ROXML gem. Big thanks to Ben Woosley for his extremely inspiring work.
|
|
170
170
|
|
|
171
|
-
* Copyright (c) 2011-
|
|
171
|
+
* Copyright (c) 2011-2020 Nick Sutterer <apotonick@gmail.com>
|
|
172
172
|
* ROXML is Copyright (c) 2004-2009 Ben Woosley, Zak Mandhro and Anders Engstrom.
|
|
173
173
|
|
|
174
|
-
Representable is released under the [MIT License](
|
|
174
|
+
Representable is released under the [MIT License](https://www.opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
1
2
|
require 'bundler/setup'
|
|
2
3
|
require 'rake/testtask'
|
|
3
4
|
|
|
@@ -9,9 +10,3 @@ Rake::TestTask.new(:test) do |test|
|
|
|
9
10
|
test.test_files = FileList['test/**/*_test.rb']
|
|
10
11
|
test.verbose = true
|
|
11
12
|
end
|
|
12
|
-
|
|
13
|
-
Rake::TestTask.new(:dtest) do |test|
|
|
14
|
-
test.libs << 'test-with-deprecations'
|
|
15
|
-
test.test_files = FileList['test-with-deprecations/**/*_test.rb']
|
|
16
|
-
test.verbose = true
|
|
17
|
-
end
|
|
@@ -1,8 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uber/delegates'
|
|
4
|
+
|
|
1
5
|
module Representable
|
|
2
6
|
# The Binding provides methods to read/write the fragment for one property.
|
|
3
7
|
#
|
|
4
8
|
# Actually parsing the fragment from the document happens in Binding#read, everything after that is generic.
|
|
5
9
|
class Binding
|
|
10
|
+
class Map < Array
|
|
11
|
+
def call(method, options)
|
|
12
|
+
each do |bin|
|
|
13
|
+
options[:binding] = bin # this is so much faster than options.merge().
|
|
14
|
+
bin.send(method, options)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# TODO: Merge with Definitions.
|
|
19
|
+
def <<(binding) # can be slow. this is compile time code.
|
|
20
|
+
(existing = find { |bin| bin.name == binding.name }) ? self[index(existing)] = binding : super(binding)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
6
24
|
class FragmentNotFound
|
|
7
25
|
end
|
|
8
26
|
|
|
@@ -29,12 +47,12 @@ module Representable
|
|
|
29
47
|
module Deprecatable
|
|
30
48
|
# Retrieve value and write fragment to the doc.
|
|
31
49
|
def compile_fragment(options)
|
|
32
|
-
render_pipeline(nil, options).(nil, options)
|
|
50
|
+
render_pipeline(nil, options).call(nil, options)
|
|
33
51
|
end
|
|
34
52
|
|
|
35
53
|
# Parse value from doc and update the model property.
|
|
36
54
|
def uncompile_fragment(options)
|
|
37
|
-
parse_pipeline(options[:doc], options).(options[:doc], options)
|
|
55
|
+
parse_pipeline(options[:doc], options).call(options[:doc], options)
|
|
38
56
|
end
|
|
39
57
|
end
|
|
40
58
|
include Deprecatable
|
|
@@ -43,7 +61,7 @@ module Representable
|
|
|
43
61
|
def evaluate_option(name, input, options)
|
|
44
62
|
proc = self[name]
|
|
45
63
|
# puts "@@@@@ #{self.inspect}, #{name}...... #{self[name]}"
|
|
46
|
-
proc.(send(:exec_context, options), options.merge(user_options: options[:options][:user_options], input: input)) # from Uber::Options::Value. # NOTE: this can also be the Proc object if it's not wrapped by Uber:::Value.
|
|
64
|
+
proc.call(exec_context: send(:exec_context, options), keyword_arguments: options.merge(user_options: options[:options][:user_options], input: input)) # from Uber::Options::Value. # NOTE: this can also be the Proc object if it's not wrapped by Uber:::Value.
|
|
47
65
|
end
|
|
48
66
|
end
|
|
49
67
|
include EvaluateOption
|
|
@@ -53,29 +71,30 @@ module Representable
|
|
|
53
71
|
end
|
|
54
72
|
|
|
55
73
|
def skipable_empty_value?(value)
|
|
56
|
-
value.nil? and
|
|
74
|
+
value.nil? and !(self[:render_nil])
|
|
57
75
|
end
|
|
58
76
|
|
|
59
77
|
def default_for(value)
|
|
60
78
|
return self[:default] if skipable_empty_value?(value)
|
|
79
|
+
|
|
61
80
|
value
|
|
62
81
|
end
|
|
63
82
|
|
|
64
83
|
attr_accessor :cached_representer
|
|
65
84
|
|
|
66
|
-
require
|
|
85
|
+
require 'representable/pipeline_factories'
|
|
67
86
|
include Factories
|
|
68
87
|
|
|
69
|
-
|
|
88
|
+
private
|
|
70
89
|
|
|
71
90
|
def setup_exec_context!
|
|
72
|
-
@exec_context = ->(options) { options[:represented] }
|
|
73
|
-
@exec_context = ->(
|
|
74
|
-
@exec_context = ->(options) { options[:decorator] }
|
|
91
|
+
@exec_context = ->(options) { options[:represented] } unless self[:exec_context]
|
|
92
|
+
@exec_context = ->(_options) { self } if self[:exec_context] == :binding
|
|
93
|
+
@exec_context = ->(options) { options[:decorator] } if self[:exec_context] == :decorator
|
|
75
94
|
end
|
|
76
95
|
|
|
77
96
|
def exec_context(options)
|
|
78
|
-
@exec_context.(options)
|
|
97
|
+
@exec_context.call(options)
|
|
79
98
|
end
|
|
80
99
|
|
|
81
100
|
def parse_pipeline(input, options)
|
|
@@ -90,8 +109,9 @@ module Representable
|
|
|
90
109
|
module Collection
|
|
91
110
|
def skipable_empty_value?(value)
|
|
92
111
|
# TODO: this can be optimized, again.
|
|
93
|
-
return true if value.nil?
|
|
94
|
-
|
|
112
|
+
return true if value.nil? && !(self[:render_nil]) # FIXME: test this without the "and"
|
|
113
|
+
|
|
114
|
+
true if (self[:render_empty] == false) && value && value.empty? # TODO: change in 2.0, don't render emtpy.
|
|
95
115
|
end
|
|
96
116
|
end
|
|
97
117
|
end
|
data/lib/representable/cached.rb
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
gem 'dry-types', '>= 1.0.0'
|
|
2
|
+
require "dry-types"
|
|
2
3
|
|
|
3
4
|
module Representable
|
|
4
5
|
module Coercion
|
|
6
|
+
module Types
|
|
7
|
+
include Dry::Types()
|
|
8
|
+
end
|
|
5
9
|
class Coercer
|
|
6
10
|
def initialize(type)
|
|
7
11
|
@type = type
|
|
8
12
|
end
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def call(input, options)
|
|
13
|
-
Virtus::Attribute.build(@type).coerce(input)
|
|
14
|
+
def call(input, _options)
|
|
15
|
+
@type.call(input)
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
|
|
@@ -34,4 +36,4 @@ module Representable
|
|
|
34
36
|
end
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
|
-
end
|
|
39
|
+
end
|
data/lib/representable/config.rb
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
require 'declarative/definitions'
|
|
2
|
+
|
|
1
3
|
module Representable
|
|
4
|
+
autoload :Option, 'representable/option'
|
|
5
|
+
|
|
2
6
|
# Stores Definitions from ::property. It preserves the adding order (1.9+).
|
|
3
7
|
# Same-named properties get overridden, just like in a Hash.
|
|
4
8
|
#
|
|
@@ -20,16 +24,17 @@ module Representable
|
|
|
20
24
|
|
|
21
25
|
def wrap=(value)
|
|
22
26
|
value = value.to_s if value.is_a?(Symbol)
|
|
23
|
-
@wrap = ::
|
|
27
|
+
@wrap = ::Representable::Option(value)
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
# Computes the wrap string or returns false.
|
|
27
|
-
def wrap_for(represented,
|
|
31
|
+
def wrap_for(represented, options = {}, &block)
|
|
28
32
|
return unless @wrap
|
|
29
33
|
|
|
30
|
-
value = @wrap.(represented,
|
|
34
|
+
value = @wrap.(exec_context: represented, keyword_arguments: options.to_hash)
|
|
31
35
|
|
|
32
36
|
return value if value != true
|
|
37
|
+
|
|
33
38
|
infer_name_for(represented.class.name)
|
|
34
39
|
end
|
|
35
40
|
|
data/lib/representable/debug.rb
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
1
3
|
module Representable
|
|
2
4
|
module Debug
|
|
5
|
+
module_function def _representable_logger
|
|
6
|
+
@logger ||= Logger.new(STDOUT)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module_function def representable_log(message)
|
|
10
|
+
_representable_logger.debug { message }
|
|
11
|
+
end
|
|
12
|
+
|
|
3
13
|
def update_properties_from(doc, options, format)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
puts "[Deserialize] document #{doc.inspect}"
|
|
14
|
+
representable_log "[Deserialize]........."
|
|
15
|
+
representable_log "[Deserialize] document #{doc.inspect}"
|
|
7
16
|
super
|
|
8
17
|
end
|
|
9
18
|
|
|
10
19
|
def create_representation_with(doc, options, format)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
puts "[Serialize]"
|
|
20
|
+
representable_log "[Serialize]........."
|
|
21
|
+
representable_log "[Serialize]"
|
|
14
22
|
super
|
|
15
23
|
end
|
|
16
24
|
|
|
@@ -22,13 +30,13 @@ module Representable
|
|
|
22
30
|
|
|
23
31
|
module Binding
|
|
24
32
|
def evaluate_option(name, *args, &block)
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
Debug.representable_log "=====#{self[name]}" if name ==:prepare
|
|
34
|
+
Debug.representable_log (evaled = self[name]) ?
|
|
27
35
|
" #evaluate_option [#{name}]: eval!!!" :
|
|
28
36
|
" #evaluate_option [#{name}]: skipping"
|
|
29
37
|
value = super
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
Debug.representable_log " #evaluate_option [#{name}]: --> #{value}" if evaled
|
|
39
|
+
Debug.representable_log " #evaluate_option [#{name}]: -->= #{args.first}" if name == :setter
|
|
32
40
|
value
|
|
33
41
|
end
|
|
34
42
|
|
|
@@ -45,17 +53,17 @@ module Representable
|
|
|
45
53
|
|
|
46
54
|
module Pipeline::Debug
|
|
47
55
|
def call(input, options)
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
Debug.representable_log "Pipeline#call: #{inspect}"
|
|
57
|
+
Debug.representable_log " input: #{input.inspect}"
|
|
50
58
|
super
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
def evaluate(block, memo, options)
|
|
54
62
|
block.extend(Pipeline::Debug) if block.is_a?(Collect)
|
|
55
63
|
|
|
56
|
-
|
|
64
|
+
Debug.representable_log " Pipeline : -> #{_inspect_function(block)} "
|
|
57
65
|
super.tap do |res|
|
|
58
|
-
|
|
66
|
+
Debug.representable_log " Pipeline : result: #{res.inspect}"
|
|
59
67
|
end
|
|
60
68
|
end
|
|
61
69
|
|
|
@@ -70,8 +78,8 @@ module Representable
|
|
|
70
78
|
def _inspect_function(func)
|
|
71
79
|
return func.extend(Pipeline::Debug).inspect if func.is_a?(Collect)
|
|
72
80
|
return func unless func.is_a?(Proc)
|
|
81
|
+
|
|
73
82
|
File.readlines(func.source_location[0])[func.source_location[1]-1].match(/^\s+(\w+)/)[1]
|
|
74
83
|
end
|
|
75
84
|
end
|
|
76
85
|
end
|
|
77
|
-
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
require "declarative/schema"
|
|
2
|
+
|
|
1
3
|
module Representable
|
|
4
|
+
autoload :Decorator, "representation/decorator"
|
|
5
|
+
autoload :Definition, "representation/definition"
|
|
6
|
+
|
|
2
7
|
module Declarative
|
|
3
8
|
def representation_wrap=(name)
|
|
4
9
|
heritage.record(:representation_wrap=, name)
|
|
@@ -21,9 +26,9 @@ module Representable
|
|
|
21
26
|
# them to the original object.
|
|
22
27
|
def nested(name, options={}, &block)
|
|
23
28
|
options = options.merge(
|
|
24
|
-
getter: ->(
|
|
29
|
+
getter: ->(_opts) { self },
|
|
25
30
|
setter: ->(opts) { },
|
|
26
|
-
instance: ->(
|
|
31
|
+
instance: ->(_opts) { self },
|
|
27
32
|
)
|
|
28
33
|
|
|
29
34
|
if block
|
|
@@ -64,4 +69,4 @@ module Representable
|
|
|
64
69
|
|
|
65
70
|
alias_method :representable_attrs, :definitions
|
|
66
71
|
end
|
|
67
|
-
end
|
|
72
|
+
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'declarative/definitions'
|
|
2
2
|
|
|
3
3
|
module Representable
|
|
4
|
+
autoload :Pipeline, "representable/pipeline"
|
|
5
|
+
autoload :Populator, "representable/populator"
|
|
6
|
+
autoload :Option, "representable/option"
|
|
7
|
+
|
|
4
8
|
# Created at class compile time. Keeps configuration options for one property.
|
|
5
9
|
class Definition < ::Declarative::Definitions::Definition
|
|
6
10
|
|
|
@@ -53,6 +57,7 @@ module Representable
|
|
|
53
57
|
|
|
54
58
|
def representable?
|
|
55
59
|
return if self[:representable] == false
|
|
60
|
+
|
|
56
61
|
self[:representable] or typed?
|
|
57
62
|
end
|
|
58
63
|
|
|
@@ -101,7 +106,7 @@ module Representable
|
|
|
101
106
|
@runtime_options = {}
|
|
102
107
|
|
|
103
108
|
for name, value in options
|
|
104
|
-
value = ::
|
|
109
|
+
value = ::Representable::Option(value) if dynamic_options.include?(name)
|
|
105
110
|
@runtime_options[name] = value
|
|
106
111
|
end
|
|
107
112
|
end
|
|
@@ -11,11 +11,11 @@ module Representable
|
|
|
11
11
|
ReadFragment = ->(input, options) { options[:binding].read(input, options[:as]) }
|
|
12
12
|
Reader = ->(input, options) { options[:binding].evaluate_option(:reader, input, options) }
|
|
13
13
|
|
|
14
|
-
StopOnNotFound = ->(input,
|
|
14
|
+
StopOnNotFound = ->(input, _options) do
|
|
15
15
|
Binding::FragmentNotFound == input ? Pipeline::Stop : input
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
StopOnNil = ->(input,
|
|
18
|
+
StopOnNil = ->(input, _options) do # DISCUSS: Not tested/used, yet.
|
|
19
19
|
input.nil? ? Pipeline::Stop : input
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -103,6 +103,7 @@ module Representable
|
|
|
103
103
|
|
|
104
104
|
return input if options[:options][:include]&&res
|
|
105
105
|
return input if options[:options][:exclude]&&!res
|
|
106
|
+
|
|
106
107
|
Pipeline::Stop
|
|
107
108
|
end
|
|
108
|
-
end
|
|
109
|
+
end
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Representable
|
|
2
4
|
module Hash
|
|
3
5
|
module AllowSymbols
|
|
4
|
-
|
|
6
|
+
private
|
|
7
|
+
|
|
5
8
|
def filter_wrap_for(data, *args)
|
|
6
9
|
super(Conversion.stringify_keys(data), *args)
|
|
7
10
|
end
|
|
@@ -11,17 +14,12 @@ module Representable
|
|
|
11
14
|
end
|
|
12
15
|
end
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
# DISCUSS: we could think about mixin in IndifferentAccess here (either hashie or ActiveSupport).
|
|
16
|
-
# or decorating the hash.
|
|
17
|
+
module Conversion
|
|
17
18
|
def self.stringify_keys(hash)
|
|
18
|
-
hash
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
hash[k.to_s] = hash.delete(k)
|
|
22
|
-
end
|
|
23
|
-
hash
|
|
19
|
+
hash.keys.collect do |key|
|
|
20
|
+
[ key.to_s, hash[key] ]
|
|
21
|
+
end.to_h
|
|
24
22
|
end
|
|
25
23
|
end
|
|
26
24
|
end
|
|
27
|
-
end
|
|
25
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'representable/hash'
|
|
2
|
+
|
|
1
3
|
module Representable::Hash
|
|
2
4
|
module Collection
|
|
3
5
|
include Representable::Hash
|
|
@@ -20,7 +22,7 @@ module Representable::Hash
|
|
|
20
22
|
# TODO: revise lonely collection and build separate pipeline where we just use Serialize, etc.
|
|
21
23
|
|
|
22
24
|
def create_representation_with(doc, options, format)
|
|
23
|
-
options = normalize_options(options)
|
|
25
|
+
options = normalize_options(**options)
|
|
24
26
|
options[:_self] = options
|
|
25
27
|
|
|
26
28
|
bin = representable_bindings_for(format, options).first
|
|
@@ -30,7 +32,7 @@ module Representable::Hash
|
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def update_properties_from(doc, options, format)
|
|
33
|
-
options = normalize_options(options)
|
|
35
|
+
options = normalize_options(**options)
|
|
34
36
|
options[:_self] = options
|
|
35
37
|
|
|
36
38
|
bin = representable_bindings_for(format, options).first
|
data/lib/representable/hash.rb
CHANGED
|
@@ -6,6 +6,9 @@ module Representable
|
|
|
6
6
|
# If you plan to write your own representer for a new media type, try to use this module (e.g., check how JSON reuses Hash's internal
|
|
7
7
|
# architecture).
|
|
8
8
|
module Hash
|
|
9
|
+
autoload :Collection, 'representable/hash/collection'
|
|
10
|
+
autoload :AllowSymbols, 'representable/hash/allow_symbols'
|
|
11
|
+
|
|
9
12
|
def self.included(base)
|
|
10
13
|
base.class_eval do
|
|
11
14
|
include Representable # either in Hero or HeroRepresentation.
|
|
@@ -34,7 +37,7 @@ module Representable
|
|
|
34
37
|
hash = create_representation_with({}, options, binding_builder)
|
|
35
38
|
|
|
36
39
|
return hash if options[:wrap] == false
|
|
37
|
-
return hash unless wrap = options[:wrap] || representation_wrap(options)
|
|
40
|
+
return hash unless (wrap = options[:wrap] || representation_wrap(options))
|
|
38
41
|
|
|
39
42
|
{wrap => hash}
|
|
40
43
|
end
|
|
@@ -45,7 +48,8 @@ module Representable
|
|
|
45
48
|
private
|
|
46
49
|
def filter_wrap(data, options)
|
|
47
50
|
return data if options[:wrap] == false
|
|
48
|
-
return data unless wrap = options[:wrap] || representation_wrap(options)
|
|
51
|
+
return data unless (wrap = options[:wrap] || representation_wrap(options))
|
|
52
|
+
|
|
49
53
|
filter_wrap_for(data, wrap)
|
|
50
54
|
end
|
|
51
55
|
|
|
@@ -20,8 +20,9 @@ module Representable
|
|
|
20
20
|
def filter_keys_for!(hash, options)
|
|
21
21
|
excluding = options[:exclude]
|
|
22
22
|
# TODO: use same filtering method as in normal representer in Representable#create_representation_with.
|
|
23
|
-
return hash unless props = options.delete(:exclude) || options.delete(:include)
|
|
24
|
-
|
|
23
|
+
return hash unless (props = (options.delete(:exclude) || options.delete(:include)))
|
|
24
|
+
|
|
25
|
+
hash.select { |k, _v| excluding ? !props.include?(k.to_sym) : props.include?(k.to_sym) }
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
28
|
end
|
data/lib/representable/insert.rb
CHANGED
data/lib/representable/json.rb
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
require "
|
|
1
|
+
gem "multi_json", '>= 1.14.1'
|
|
2
|
+
require "multi_json"
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
require "multi_json"
|
|
6
|
-
rescue LoadError => _
|
|
7
|
-
abort "Missing dependency 'multi_json' for Representable::JSON. See dependencies section in README.md for details."
|
|
8
|
-
end
|
|
4
|
+
require "representable"
|
|
9
5
|
|
|
10
6
|
module Representable
|
|
11
7
|
# Brings #to_json and #from_json to your object.
|
|
12
8
|
module JSON
|
|
9
|
+
autoload :Collection, "representable/json/collection"
|
|
10
|
+
|
|
13
11
|
extend Hash::ClassMethods
|
|
14
12
|
include Hash
|
|
15
13
|
|