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.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +23 -0
  3. data/CHANGES.md +14 -0
  4. data/Gemfile +4 -7
  5. data/LICENSE +1 -1
  6. data/README.md +12 -12
  7. data/Rakefile +1 -6
  8. data/lib/representable/binding.rb +32 -12
  9. data/lib/representable/cached.rb +1 -1
  10. data/lib/representable/coercion.rb +8 -6
  11. data/lib/representable/config.rb +8 -3
  12. data/lib/representable/debug.rb +23 -15
  13. data/lib/representable/declarative.rb +8 -3
  14. data/lib/representable/decorator.rb +1 -1
  15. data/lib/representable/definition.rb +7 -2
  16. data/lib/representable/deserializer.rb +4 -3
  17. data/lib/representable/for_collection.rb +1 -1
  18. data/lib/representable/hash/allow_symbols.rb +9 -11
  19. data/lib/representable/hash/binding.rb +1 -0
  20. data/lib/representable/hash/collection.rb +4 -2
  21. data/lib/representable/hash.rb +6 -2
  22. data/lib/representable/hash_methods.rb +3 -2
  23. data/lib/representable/insert.rb +1 -1
  24. data/lib/representable/json/collection.rb +3 -0
  25. data/lib/representable/json/hash.rb +1 -0
  26. data/lib/representable/json.rb +5 -7
  27. data/lib/representable/object/binding.rb +5 -1
  28. data/lib/representable/object.rb +1 -1
  29. data/lib/representable/option.rb +19 -0
  30. data/lib/representable/pipeline.rb +3 -2
  31. data/lib/representable/pipeline_factories.rb +4 -2
  32. data/lib/representable/populator.rb +1 -1
  33. data/lib/representable/represent.rb +1 -0
  34. data/lib/representable/serializer.rb +2 -1
  35. data/lib/representable/version.rb +1 -1
  36. data/lib/representable/xml/binding.rb +5 -6
  37. data/lib/representable/xml.rb +7 -10
  38. data/lib/representable/yaml/binding.rb +1 -0
  39. data/lib/representable/yaml.rb +3 -3
  40. data/lib/representable.rb +18 -25
  41. data/representable.gemspec +3 -3
  42. data/test/as_test.rb +4 -4
  43. data/test/binding_test.rb +10 -10
  44. data/test/cached_test.rb +19 -19
  45. data/test/class_test.rb +7 -7
  46. data/test/coercion_test.rb +33 -22
  47. data/test/config/inherit_test.rb +14 -14
  48. data/test/config_test.rb +18 -18
  49. data/test/decorator_scope_test.rb +3 -3
  50. data/test/decorator_test.rb +17 -17
  51. data/test/default_test.rb +7 -7
  52. data/test/definition_test.rb +32 -32
  53. data/test/{example.rb → examples/example.rb} +0 -0
  54. data/test/exec_context_test.rb +6 -6
  55. data/test/features_test.rb +3 -3
  56. data/test/filter_test.rb +6 -6
  57. data/test/for_collection_test.rb +2 -2
  58. data/test/generic_test.rb +3 -3
  59. data/test/getter_setter_test.rb +5 -5
  60. data/test/hash_test.rb +19 -19
  61. data/test/heritage_test.rb +4 -4
  62. data/test/if_test.rb +6 -6
  63. data/test/include_exclude_test.rb +12 -12
  64. data/test/inherit_test.rb +15 -15
  65. data/test/inline_test.rb +11 -11
  66. data/test/instance_test.rb +29 -29
  67. data/test/is_representable_test.rb +10 -10
  68. data/test/json_test.rb +7 -7
  69. data/test/lonely_test.rb +16 -16
  70. data/test/nested_test.rb +7 -7
  71. data/test/object_test.rb +7 -7
  72. data/test/option_test.rb +36 -0
  73. data/test/parse_pipeline_test.rb +3 -3
  74. data/test/pipeline_test.rb +43 -43
  75. data/test/populator_test.rb +15 -15
  76. data/test/prepare_test.rb +2 -2
  77. data/test/private_options_test.rb +2 -2
  78. data/test/reader_writer_test.rb +2 -2
  79. data/test/render_nil_test.rb +2 -2
  80. data/test/represent_test.rb +4 -4
  81. data/test/representable_test.rb +27 -27
  82. data/test/schema_test.rb +5 -5
  83. data/test/serialize_deserialize_test.rb +2 -2
  84. data/test/skip_test.rb +10 -10
  85. data/test/stringify_hash_test.rb +3 -3
  86. data/test/test_helper.rb +4 -2
  87. data/test/uncategorized_test.rb +10 -10
  88. data/test/user_options_test.rb +4 -4
  89. data/test/wrap_test.rb +11 -11
  90. data/test/xml_namespace_test.rb +1 -1
  91. data/test/xml_test.rb +6 -6
  92. data/test/yaml_test.rb +20 -20
  93. metadata +16 -11
  94. data/.travis.yml +0 -16
  95. data/lib/representable/autoload.rb +0 -14
  96. data/test/mongoid_test.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 04ca3309b8af78dd1eaa8b4d47c457323180a881
4
- data.tar.gz: c7d43dc372fc53576a6b64f22d3fc0bd1bff5a4e
2
+ SHA256:
3
+ metadata.gz: f3a1388b7570e31d62c555a87d6165793e9d095cf1bed18c04cb8cbe86bc2ba2
4
+ data.tar.gz: 43e418db52478d3d4fc33f505ce86d840fcb666a8abc83e20269bbfab4c53a3a
5
5
  SHA512:
6
- metadata.gz: 528696ff8d8eae7b409566d9831a0117a90a361fdabe5a0345d0e5accac5cfbb2f3bfae5a34589000b5bdbf2632f7951356861215d210172c602b581694e68dc
7
- data.tar.gz: 4d7409a62a9a25d31fc1c67d20e2b32b9cd0a1d8e9987b2cbe118bd4e069fe271dd82127f3e7656b92f01e8f1266524965def4089e439b4a1eac370e13a06bff
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 'https://rubygems.org'
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 - 2013 Nick Sutterer and the roar contributors
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
- [![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat)
6
- [![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/)
7
- [![Build
8
- Status](https://travis-ci.org/trailblazer/representable.svg)](https://travis-ci.org/trailblazer/representable)
5
+ ![Build
6
+ Status](https://github.com/trailblazer/representable/actions/workflows/ci.yml/badge.svg?branch=master)
9
7
  [![Gem Version](https://badge.fury.io/rb/representable.svg)](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](http://github.com/apotonick/roar) gem first, save work and time and make the world a better place instead.
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](http://trailblazer.to/gems/representable/3.0/api.html) can be found on the Trailblazer site.
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](http://trailblazer.to/gems/representable/3.0/api.html#symbol-keys) and does _not_ pick up symbol 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](http://trailblazer.to/gems/representable/).
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 >= 1.9.3.
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-2016 Nick Sutterer <apotonick@gmail.com>
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](http://www.opensource.org/licenses/MIT).
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 not self[:render_nil]
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 "representable/pipeline_factories"
85
+ require 'representable/pipeline_factories'
67
86
  include Factories
68
87
 
69
- private
88
+ private
70
89
 
71
90
  def setup_exec_context!
72
- @exec_context = ->(options) { options[:represented] } unless self[:exec_context]
73
- @exec_context = ->(options) { self } if self[:exec_context] == :binding
74
- @exec_context = ->(options) { options[:decorator] } if self[:exec_context] == :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? and not self[:render_nil] # FIXME: test this without the "and"
94
- return true if self[:render_empty] == false and value and value.size == 0 # TODO: change in 2.0, don't render emtpy.
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
@@ -19,4 +19,4 @@ module Representable
19
19
  self.class.map
20
20
  end
21
21
  end
22
- end
22
+ end
@@ -1,16 +1,18 @@
1
- require "virtus"
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
- # This gets called when the :render_filter or :parse_filter option is evaluated.
11
- # Usually the Coercer instance is an element in a Pipeline to allow >1 filters per property.
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
@@ -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 = ::Declarative::Option(value, instance_exec: true, callable: Uber::Callable)
27
+ @wrap = ::Representable::Option(value)
24
28
  end
25
29
 
26
30
  # Computes the wrap string or returns false.
27
- def wrap_for(represented, *args, &block)
31
+ def wrap_for(represented, options = {}, &block)
28
32
  return unless @wrap
29
33
 
30
- value = @wrap.(represented, *args)
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
 
@@ -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
- puts
5
- puts "[Deserialize]........."
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
- puts
12
- puts "[Serialize]........."
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
- puts "=====#{self[name]}" if name ==:prepare
26
- puts (evaled = self[name]) ?
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
- puts " #evaluate_option [#{name}]: --> #{value}" if evaled
31
- puts " #evaluate_option [#{name}]: -->= #{args.first}" if name == :setter
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
- puts "Pipeline#call: #{inspect}"
49
- puts " input: #{input.inspect}"
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
- puts " Pipeline : -> #{_inspect_function(block)} "
64
+ Debug.representable_log " Pipeline : -> #{_inspect_function(block)} "
57
65
  super.tap do |res|
58
- puts " Pipeline : result: #{res.inspect}"
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: ->(opts) { self },
29
+ getter: ->(_opts) { self },
25
30
  setter: ->(opts) { },
26
- instance: ->(opts) { self },
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,5 +1,5 @@
1
- require "representable"
2
1
  require "uber/inheritable_attr"
2
+ require "representable"
3
3
 
4
4
  module Representable
5
5
  class Decorator
@@ -1,6 +1,10 @@
1
- require "representable/populator"
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 = ::Declarative::Option(value, instance_exec: true, callable: Uber::Callable) if dynamic_options.include?(name)
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, options) do
14
+ StopOnNotFound = ->(input, _options) do
15
15
  Binding::FragmentNotFound == input ? Pipeline::Stop : input
16
16
  end
17
17
 
18
- StopOnNil = ->(input, options) do # DISCUSS: Not tested/used, yet.
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
@@ -24,4 +24,4 @@ module Representable
24
24
  @collection_representer = collection_representer!(options)
25
25
  end
26
26
  end
27
- end
27
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Representable
2
4
  module Hash
3
5
  module AllowSymbols
4
- private
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
- class Conversion
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 = hash.dup
19
-
20
- hash.keys.each do |k|
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
@@ -5,6 +5,7 @@ module Representable
5
5
  class Binding < Representable::Binding
6
6
  def self.build_for(definition)
7
7
  return Collection.new(definition) if definition.array?
8
+
8
9
  new(definition)
9
10
  end
10
11
 
@@ -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
@@ -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
- hash.reject { |k,v| excluding ? props.include?(k.to_sym) : !props.include?(k.to_sym) }
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
@@ -35,4 +35,4 @@ module Representable
35
35
 
36
36
  Insert = Pipeline::Function::Insert.new
37
37
  end # Pipeline
38
- end
38
+ end
@@ -1,3 +1,6 @@
1
+ require 'representable/json'
2
+ require 'representable/hash/collection'
3
+
1
4
  module Representable::JSON
2
5
  module Collection
3
6
  include Representable::JSON
@@ -1,3 +1,4 @@
1
+ require 'representable/json'
1
2
  require 'representable/hash_methods'
2
3
 
3
4
  module Representable::JSON
@@ -1,15 +1,13 @@
1
- require "representable/hash"
2
- require "representable/json/collection"
1
+ gem "multi_json", '>= 1.14.1'
2
+ require "multi_json"
3
3
 
4
- begin
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