active_model_serializers 0.8.3 → 0.10.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 +4 -4
- data/.github/ISSUE_TEMPLATE.md +29 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +104 -0
- data/.rubocop_todo.yml +167 -0
- data/.simplecov +110 -0
- data/.travis.yml +39 -24
- data/CHANGELOG.md +465 -6
- data/CONTRIBUTING.md +105 -0
- data/Gemfile +50 -1
- data/{MIT-LICENSE.txt → MIT-LICENSE} +3 -2
- data/README.md +102 -590
- data/Rakefile +93 -8
- data/active_model_serializers.gemspec +65 -23
- data/appveyor.yml +24 -0
- data/bin/bench +171 -0
- data/bin/bench_regression +316 -0
- data/bin/serve_benchmark +39 -0
- data/docs/ARCHITECTURE.md +126 -0
- data/docs/README.md +40 -0
- data/docs/STYLE.md +58 -0
- data/docs/general/adapters.md +245 -0
- data/docs/general/caching.md +52 -0
- data/docs/general/configuration_options.md +100 -0
- data/docs/general/deserialization.md +100 -0
- data/docs/general/getting_started.md +133 -0
- data/docs/general/instrumentation.md +40 -0
- data/docs/general/key_transforms.md +40 -0
- data/docs/general/logging.md +14 -0
- data/docs/general/rendering.md +255 -0
- data/docs/general/serializers.md +372 -0
- data/docs/how-open-source-maintained.jpg +0 -0
- data/docs/howto/add_pagination_links.md +139 -0
- data/docs/howto/add_root_key.md +51 -0
- data/docs/howto/outside_controller_use.md +58 -0
- data/docs/howto/passing_arbitrary_options.md +27 -0
- data/docs/howto/serialize_poro.md +32 -0
- data/docs/howto/test.md +152 -0
- data/docs/integrations/ember-and-json-api.md +112 -0
- data/docs/integrations/grape.md +19 -0
- data/docs/jsonapi/errors.md +56 -0
- data/docs/jsonapi/schema/schema.json +366 -0
- data/docs/jsonapi/schema.md +151 -0
- data/docs/rfcs/0000-namespace.md +106 -0
- data/docs/rfcs/template.md +15 -0
- data/lib/action_controller/serialization.rb +31 -36
- data/lib/active_model/serializable_resource.rb +11 -0
- data/lib/active_model/serializer/adapter/attributes.rb +15 -0
- data/lib/active_model/serializer/adapter/base.rb +16 -0
- data/lib/active_model/serializer/adapter/json.rb +15 -0
- data/lib/active_model/serializer/adapter/json_api.rb +15 -0
- data/lib/active_model/serializer/adapter/null.rb +15 -0
- data/lib/active_model/serializer/adapter.rb +24 -0
- data/lib/active_model/serializer/array_serializer.rb +9 -0
- data/lib/active_model/serializer/association.rb +19 -0
- data/lib/active_model/serializer/associations.rb +87 -220
- data/lib/active_model/serializer/attribute.rb +25 -0
- data/lib/active_model/serializer/attributes.rb +82 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
- data/lib/active_model/serializer/caching.rb +333 -0
- data/lib/active_model/serializer/collection_reflection.rb +7 -0
- data/lib/active_model/serializer/collection_serializer.rb +64 -0
- data/lib/active_model/serializer/configuration.rb +35 -0
- data/lib/active_model/serializer/error_serializer.rb +10 -0
- data/lib/active_model/serializer/errors_serializer.rb +27 -0
- data/lib/active_model/serializer/field.rb +90 -0
- data/lib/active_model/serializer/fieldset.rb +31 -0
- data/lib/active_model/serializer/has_many_reflection.rb +10 -0
- data/lib/active_model/serializer/has_one_reflection.rb +10 -0
- data/lib/active_model/serializer/include_tree.rb +111 -0
- data/lib/active_model/serializer/links.rb +35 -0
- data/lib/active_model/serializer/lint.rb +146 -0
- data/lib/active_model/serializer/meta.rb +29 -0
- data/lib/active_model/serializer/null.rb +17 -0
- data/lib/active_model/serializer/reflection.rb +147 -0
- data/lib/active_model/serializer/singular_reflection.rb +7 -0
- data/lib/active_model/serializer/type.rb +25 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer.rb +158 -481
- data/lib/active_model_serializers/adapter/attributes.rb +76 -0
- data/lib/active_model_serializers/adapter/base.rb +83 -0
- data/lib/active_model_serializers/adapter/json.rb +21 -0
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
- data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
- data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
- data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
- data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +62 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +52 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +37 -0
- data/lib/active_model_serializers/adapter/json_api.rb +516 -0
- data/lib/active_model_serializers/adapter/null.rb +9 -0
- data/lib/active_model_serializers/adapter.rb +92 -0
- data/lib/active_model_serializers/callbacks.rb +55 -0
- data/lib/active_model_serializers/deprecate.rb +55 -0
- data/lib/active_model_serializers/deserialization.rb +13 -0
- data/lib/active_model_serializers/json_pointer.rb +14 -0
- data/lib/active_model_serializers/key_transform.rb +70 -0
- data/lib/active_model_serializers/logging.rb +122 -0
- data/lib/active_model_serializers/model.rb +49 -0
- data/lib/active_model_serializers/railtie.rb +46 -0
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +65 -0
- data/lib/active_model_serializers/serializable_resource.rb +81 -0
- data/lib/active_model_serializers/serialization_context.rb +32 -0
- data/lib/active_model_serializers/test/schema.rb +138 -0
- data/lib/active_model_serializers/test/serializer.rb +125 -0
- data/lib/active_model_serializers/test.rb +7 -0
- data/lib/active_model_serializers.rb +32 -89
- data/lib/generators/rails/USAGE +6 -0
- data/lib/generators/rails/resource_override.rb +10 -0
- data/lib/generators/rails/serializer_generator.rb +36 -0
- data/lib/generators/rails/templates/serializer.rb.erb +8 -0
- data/lib/grape/active_model_serializers.rb +14 -0
- data/lib/grape/formatters/active_model_serializers.rb +15 -0
- data/lib/grape/helpers/active_model_serializers.rb +16 -0
- data/test/action_controller/adapter_selector_test.rb +53 -0
- data/test/action_controller/explicit_serializer_test.rb +134 -0
- data/test/action_controller/json/include_test.rb +167 -0
- data/test/action_controller/json_api/deserialization_test.rb +112 -0
- data/test/action_controller/json_api/errors_test.rb +41 -0
- data/test/action_controller/json_api/linked_test.rb +197 -0
- data/test/action_controller/json_api/pagination_test.rb +116 -0
- data/test/action_controller/json_api/transform_test.rb +181 -0
- data/test/action_controller/serialization_scope_name_test.rb +229 -0
- data/test/action_controller/serialization_test.rb +469 -0
- data/test/active_model_serializers/adapter_for_test.rb +208 -0
- data/test/active_model_serializers/json_pointer_test.rb +20 -0
- data/test/active_model_serializers/key_transform_test.rb +263 -0
- data/test/active_model_serializers/logging_test.rb +77 -0
- data/test/active_model_serializers/model_test.rb +9 -0
- data/test/active_model_serializers/railtie_test_isolated.rb +63 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +58 -0
- data/test/active_model_serializers/test/schema_test.rb +130 -0
- data/test/active_model_serializers/test/serializer_test.rb +62 -0
- data/test/active_record_test.rb +9 -0
- data/test/adapter/deprecation_test.rb +100 -0
- data/test/adapter/json/belongs_to_test.rb +45 -0
- data/test/adapter/json/collection_test.rb +90 -0
- data/test/adapter/json/has_many_test.rb +45 -0
- data/test/adapter/json/transform_test.rb +93 -0
- data/test/adapter/json_api/belongs_to_test.rb +155 -0
- data/test/adapter/json_api/collection_test.rb +95 -0
- data/test/adapter/json_api/errors_test.rb +78 -0
- data/test/adapter/json_api/fields_test.rb +87 -0
- data/test/adapter/json_api/has_many_embed_ids_test.rb +43 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
- data/test/adapter/json_api/has_many_test.rb +144 -0
- data/test/adapter/json_api/has_one_test.rb +80 -0
- data/test/adapter/json_api/json_api_test.rb +35 -0
- data/test/adapter/json_api/linked_test.rb +392 -0
- data/test/adapter/json_api/links_test.rb +93 -0
- data/test/adapter/json_api/pagination_links_test.rb +166 -0
- data/test/adapter/json_api/parse_test.rb +137 -0
- data/test/adapter/json_api/relationship_test.rb +161 -0
- data/test/adapter/json_api/relationships_test.rb +199 -0
- data/test/adapter/json_api/resource_identifier_test.rb +85 -0
- data/test/adapter/json_api/resource_meta_test.rb +100 -0
- data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
- data/test/adapter/json_api/transform_test.rb +502 -0
- data/test/adapter/json_api/type_test.rb +61 -0
- data/test/adapter/json_test.rb +45 -0
- data/test/adapter/null_test.rb +23 -0
- data/test/adapter/polymorphic_test.rb +171 -0
- data/test/adapter_test.rb +67 -0
- data/test/array_serializer_test.rb +20 -73
- data/test/benchmark/app.rb +65 -0
- data/test/benchmark/benchmarking_support.rb +67 -0
- data/test/benchmark/bm_caching.rb +119 -0
- data/test/benchmark/bm_transform.rb +34 -0
- data/test/benchmark/config.ru +3 -0
- data/test/benchmark/controllers.rb +84 -0
- data/test/benchmark/fixtures.rb +219 -0
- data/test/cache_test.rb +485 -0
- data/test/collection_serializer_test.rb +110 -0
- data/test/fixtures/active_record.rb +78 -0
- data/test/fixtures/poro.rb +282 -0
- data/test/generators/scaffold_controller_generator_test.rb +24 -0
- data/test/generators/serializer_generator_test.rb +57 -0
- data/test/grape_test.rb +82 -0
- data/test/include_tree/from_include_args_test.rb +26 -0
- data/test/include_tree/from_string_test.rb +94 -0
- data/test/include_tree/include_args_to_hash_test.rb +64 -0
- data/test/lint_test.rb +49 -0
- data/test/logger_test.rb +18 -0
- data/test/poro_test.rb +9 -0
- data/test/serializable_resource_test.rb +83 -0
- data/test/serializers/association_macros_test.rb +36 -0
- data/test/serializers/associations_test.rb +295 -0
- data/test/serializers/attribute_test.rb +151 -0
- data/test/serializers/attributes_test.rb +52 -0
- data/test/serializers/caching_configuration_test_isolated.rb +170 -0
- data/test/serializers/configuration_test.rb +32 -0
- data/test/serializers/fieldset_test.rb +14 -0
- data/test/serializers/meta_test.rb +196 -0
- data/test/serializers/options_test.rb +21 -0
- data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
- data/test/serializers/root_test.rb +21 -0
- data/test/serializers/serialization_test.rb +55 -0
- data/test/serializers/serializer_for_test.rb +134 -0
- data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/isolated_unit.rb +79 -0
- data/test/support/rails5_shims.rb +47 -0
- data/test/support/rails_app.rb +45 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
- data/test/support/schemas/custom/show.json +7 -0
- data/test/support/schemas/hyper_schema.json +93 -0
- data/test/support/schemas/render_using_json_api.json +43 -0
- data/test/support/schemas/simple_json_pointers.json +10 -0
- data/test/support/serialization_testing.rb +53 -0
- data/test/test_helper.rb +48 -23
- metadata +449 -43
- data/DESIGN.textile +0 -586
- data/Gemfile.edge +0 -9
- data/bench/perf.rb +0 -43
- data/cruft.md +0 -19
- data/lib/active_model/array_serializer.rb +0 -104
- data/lib/active_record/serializer_override.rb +0 -16
- data/lib/generators/resource_override.rb +0 -13
- data/lib/generators/serializer/USAGE +0 -9
- data/lib/generators/serializer/serializer_generator.rb +0 -42
- data/lib/generators/serializer/templates/serializer.rb +0 -19
- data/test/association_test.rb +0 -592
- data/test/caching_test.rb +0 -96
- data/test/generators_test.rb +0 -85
- data/test/no_serialization_scope_test.rb +0 -34
- data/test/serialization_scope_name_test.rb +0 -67
- data/test/serialization_test.rb +0 -392
- data/test/serializer_support_test.rb +0 -51
- data/test/serializer_test.rb +0 -1465
- data/test/test_fakes.rb +0 -217
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'shellwords'
|
|
5
|
+
require 'English'
|
|
6
|
+
|
|
7
|
+
############################
|
|
8
|
+
# USAGE
|
|
9
|
+
#
|
|
10
|
+
# bundle exec bin/bench_regression <ref1> <ref2>
|
|
11
|
+
# <ref1> defaults to the current branch
|
|
12
|
+
# <ref2> defaults to the master branch
|
|
13
|
+
# bundle exec bin/bench_regression current # will run on the current branch
|
|
14
|
+
# bundle exec bin/bench_regression revisions 792fb8a90 master # every revision inclusive
|
|
15
|
+
# bundle exec bin/bench_regression 792fb8a90 master --repeat-count 2 --env CACHE_ON=off
|
|
16
|
+
# bundle exec bin/bench_regression vendor
|
|
17
|
+
###########################
|
|
18
|
+
|
|
19
|
+
class BenchRegression
|
|
20
|
+
ROOT = Pathname File.expand_path(File.join(*['..', '..']), __FILE__)
|
|
21
|
+
TMP_DIR_NAME = File.join('tmp', 'bench')
|
|
22
|
+
TMP_DIR = File.join(ROOT, TMP_DIR_NAME)
|
|
23
|
+
E_TMP_DIR = Shellwords.shellescape(TMP_DIR)
|
|
24
|
+
load ROOT.join('bin', 'bench')
|
|
25
|
+
|
|
26
|
+
attr_reader :source_stasher
|
|
27
|
+
|
|
28
|
+
def initialize
|
|
29
|
+
@source_stasher = SourceStasher.new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class SourceStasher
|
|
33
|
+
attr_reader :gem_require_paths, :gem_paths
|
|
34
|
+
attr_writer :vendor
|
|
35
|
+
|
|
36
|
+
def initialize
|
|
37
|
+
@gem_require_paths = []
|
|
38
|
+
@gem_paths = []
|
|
39
|
+
refresh_temp_dir
|
|
40
|
+
@vendor = false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def temp_dir_empty?
|
|
44
|
+
File.directory?(TMP_DIR) &&
|
|
45
|
+
Dir[File.join(TMP_DIR, '*')].none?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def empty_temp_dir
|
|
49
|
+
return if @vendor
|
|
50
|
+
return if temp_dir_empty?
|
|
51
|
+
FileUtils.mkdir_p(TMP_DIR)
|
|
52
|
+
Dir[File.join(TMP_DIR, '*')].each do |file|
|
|
53
|
+
if File.directory?(file)
|
|
54
|
+
FileUtils.rm_rf(file)
|
|
55
|
+
else
|
|
56
|
+
FileUtils.rm(file)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def fill_temp_dir
|
|
62
|
+
vendor_files(Dir[File.join(ROOT, 'test', 'benchmark', '*.{rb,ru}')])
|
|
63
|
+
# vendor_file(File.join('bin', 'bench'))
|
|
64
|
+
housekeeping { empty_temp_dir }
|
|
65
|
+
vendor_gem('benchmark-ips')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def vendor_files(files)
|
|
69
|
+
files.each do |file|
|
|
70
|
+
vendor_file(file)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def vendor_file(file)
|
|
75
|
+
FileUtils.cp(file, File.join(TMP_DIR, File.basename(file)))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def vendor_gem(gem_name)
|
|
79
|
+
directory_name = `bundle exec gem unpack benchmark-ips --target=#{E_TMP_DIR}`[/benchmark-ips.+\d/]
|
|
80
|
+
gem_paths << File.join(TMP_DIR, directory_name)
|
|
81
|
+
gem_require_paths << File.join(TMP_DIR_NAME, directory_name, 'lib')
|
|
82
|
+
housekeeping { remove_vendored_gems }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def remove_vendored_gems
|
|
86
|
+
return if @vendor
|
|
87
|
+
FileUtils.rm_rf(*gem_paths)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def refresh_temp_dir
|
|
91
|
+
empty_temp_dir
|
|
92
|
+
fill_temp_dir
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def housekeeping
|
|
96
|
+
at_exit { yield }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
module RevisionMethods
|
|
101
|
+
module_function
|
|
102
|
+
def current_branch
|
|
103
|
+
@current_branch ||= `cat .git/HEAD | cut -d/ -f3,4,5`.chomp
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def current_revision
|
|
107
|
+
`git rev-parse --short HEAD`.chomp
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def revision_description(rev)
|
|
111
|
+
`git log --oneline -1 #{rev}`.chomp
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def revisions(start_ref, end_ref)
|
|
115
|
+
cmd = "git rev-list --reverse #{start_ref}..#{end_ref}"
|
|
116
|
+
`#{cmd}`.chomp.split("\n")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def checkout_ref(ref)
|
|
120
|
+
`git checkout #{ref}`.chomp
|
|
121
|
+
if $CHILD_STATUS
|
|
122
|
+
STDERR.puts "Checkout failed: #{ref}, #{$CHILD_STATUS.exitstatus}" unless $CHILD_STATUS.success?
|
|
123
|
+
$CHILD_STATUS.success?
|
|
124
|
+
else
|
|
125
|
+
true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def clean_head
|
|
130
|
+
system('git reset --hard --quiet')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
module ShellMethods
|
|
134
|
+
|
|
135
|
+
def sh(cmd)
|
|
136
|
+
puts cmd
|
|
137
|
+
# system(cmd)
|
|
138
|
+
run(cmd)
|
|
139
|
+
# env = {}
|
|
140
|
+
# # out = STDOUT
|
|
141
|
+
# pid = spawn(env, cmd)
|
|
142
|
+
# Process.wait(pid)
|
|
143
|
+
# pid = fork do
|
|
144
|
+
# exec cmd
|
|
145
|
+
# end
|
|
146
|
+
# Process.waitpid2(pid)
|
|
147
|
+
# puts $CHILD_STATUS.exitstatus
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
require 'pty'
|
|
151
|
+
# should consider trapping SIGINT in here
|
|
152
|
+
def run(cmd)
|
|
153
|
+
puts cmd
|
|
154
|
+
child_process = ''
|
|
155
|
+
result = ''
|
|
156
|
+
# http://stackoverflow.com/a/1162850
|
|
157
|
+
# stream output of subprocess
|
|
158
|
+
begin
|
|
159
|
+
PTY.spawn(cmd) do |stdin, _stdout, pid|
|
|
160
|
+
begin
|
|
161
|
+
# Do stuff with the output here. Just printing to show it works
|
|
162
|
+
stdin.each do |line|
|
|
163
|
+
print line
|
|
164
|
+
result << line
|
|
165
|
+
end
|
|
166
|
+
child_process = PTY.check(pid)
|
|
167
|
+
rescue Errno::EIO
|
|
168
|
+
puts 'Errno:EIO error, but this probably just means ' \
|
|
169
|
+
'that the process has finished giving output'
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
rescue PTY::ChildExited
|
|
173
|
+
puts 'The child process exited!'
|
|
174
|
+
end
|
|
175
|
+
unless (child_process && child_process.success?)
|
|
176
|
+
exitstatus = child_process.exitstatus
|
|
177
|
+
puts "FAILED: #{child_process.pid} exited with status #{exitstatus.inspect} due to failed command #{cmd}"
|
|
178
|
+
exit exitstatus || 1
|
|
179
|
+
end
|
|
180
|
+
result
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def bundle(ref)
|
|
184
|
+
system("rm -f Gemfile.lock")
|
|
185
|
+
# This is absolutely critical for bundling to work
|
|
186
|
+
Bundler.with_clean_env do
|
|
187
|
+
system("bundle check ||
|
|
188
|
+
bundle install --local ||
|
|
189
|
+
bundle install ||
|
|
190
|
+
bundle update")
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# if $CHILD_STATUS
|
|
194
|
+
# STDERR.puts "Bundle failed at: #{ref}, #{$CHILD_STATUS.exitstatus}" unless $CHILD_STATUS.success?
|
|
195
|
+
# $CHILD_STATUS.success?
|
|
196
|
+
# else
|
|
197
|
+
# false
|
|
198
|
+
# end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
include ShellMethods
|
|
202
|
+
include RevisionMethods
|
|
203
|
+
|
|
204
|
+
def benchmark_refs(ref1: nil, ref2: nil, cmd:)
|
|
205
|
+
checking_out = false
|
|
206
|
+
ref0 = current_branch
|
|
207
|
+
ref1 ||= current_branch
|
|
208
|
+
ref2 ||= 'master'
|
|
209
|
+
p [ref0, ref1, ref2, current_revision]
|
|
210
|
+
|
|
211
|
+
run_benchmark_at_ref(cmd, ref1)
|
|
212
|
+
p [ref0, ref1, ref2, current_revision]
|
|
213
|
+
run_benchmark_at_ref(cmd, ref2)
|
|
214
|
+
p [ref0, ref1, ref2, current_revision]
|
|
215
|
+
|
|
216
|
+
checking_out = true
|
|
217
|
+
checkout_ref(ref0)
|
|
218
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
219
|
+
STDERR.puts "[ERROR] #{$!.message}"
|
|
220
|
+
checkout_ref(ref0) unless checking_out
|
|
221
|
+
raise
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def benchmark_revisions(ref1: nil, ref2: nil, cmd:)
|
|
225
|
+
checking_out = false
|
|
226
|
+
ref0 = current_branch
|
|
227
|
+
ref1 ||= current_branch
|
|
228
|
+
ref2 ||= 'master'
|
|
229
|
+
|
|
230
|
+
revisions(ref1, ref2).each do |rev|
|
|
231
|
+
STDERR.puts "Checking out: #{revision_description(rev)}"
|
|
232
|
+
|
|
233
|
+
run_benchmark_at_ref(cmd, rev)
|
|
234
|
+
clean_head
|
|
235
|
+
end
|
|
236
|
+
checking_out = true
|
|
237
|
+
checkout_ref(ref0)
|
|
238
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
239
|
+
STDERR.puts "[ERROR]: #{$!.message}"
|
|
240
|
+
checkout_ref(ref0) unless checking_out
|
|
241
|
+
raise
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def run_benchmark_at_ref(cmd, ref)
|
|
245
|
+
checkout_ref(ref)
|
|
246
|
+
run_benchmark(cmd, ref)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def run_benchmark(cmd, ref = nil)
|
|
250
|
+
ref ||= current_revision
|
|
251
|
+
bundle(ref) &&
|
|
252
|
+
benchmark_tests(cmd, ref)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def benchmark_tests(cmd, ref)
|
|
256
|
+
base = E_TMP_DIR
|
|
257
|
+
# cmd.sub('bin/bench', 'tmp/revision_runner/bench')
|
|
258
|
+
# bundle = Gem.bin('bunle'
|
|
259
|
+
# Bundler.with_clean_env(&block)
|
|
260
|
+
|
|
261
|
+
# cmd = Shellwords.shelljoin(cmd)
|
|
262
|
+
# cmd = "COMMIT_HASH=#{ref} BASE=#{base} bundle exec ruby -rbenchmark/ips #{cmd}"
|
|
263
|
+
# Add vendoring benchmark/ips to load path
|
|
264
|
+
|
|
265
|
+
# CURRENT THINKING: IMPORTANT
|
|
266
|
+
# Pass into require statement as RUBYOPTS i.e. via env rather than command line argument
|
|
267
|
+
# otherwise, have a 'fast ams benchmarking' module that extends benchmarkings to add the 'ams'
|
|
268
|
+
# method but doesn't depend on benchmark-ips
|
|
269
|
+
options = {
|
|
270
|
+
commit_hash: ref,
|
|
271
|
+
base: base,
|
|
272
|
+
rubyopt: Shellwords.shellescape("-Ilib:#{source_stasher.gem_require_paths.join(':')}")
|
|
273
|
+
}
|
|
274
|
+
BenchmarkDriver.parse_argv_and_run(ARGV.dup, options)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
if $PROGRAM_NAME == __FILE__
|
|
279
|
+
benchmarking = BenchRegression.new
|
|
280
|
+
|
|
281
|
+
case ARGV[0]
|
|
282
|
+
when 'current'
|
|
283
|
+
# Run current branch only
|
|
284
|
+
|
|
285
|
+
# super simple command line parsing
|
|
286
|
+
args = ARGV.dup
|
|
287
|
+
_ = args.shift # remove 'current' from args
|
|
288
|
+
cmd = args
|
|
289
|
+
benchmarking.run_benchmark(cmd)
|
|
290
|
+
when 'revisions'
|
|
291
|
+
# Runs on every revision
|
|
292
|
+
|
|
293
|
+
# super simple command line parsing
|
|
294
|
+
args = ARGV.dup
|
|
295
|
+
_ = args.shift
|
|
296
|
+
ref1 = args.shift # remove 'revisions' from args
|
|
297
|
+
ref2 = args.shift
|
|
298
|
+
cmd = args
|
|
299
|
+
benchmarking.benchmark_revisions(ref1: ref1, ref2: ref2, cmd: cmd)
|
|
300
|
+
when 'vendor'
|
|
301
|
+
# Just prevents vendored files from being cleaned up
|
|
302
|
+
# at exit. (They are vendored at initialize.)
|
|
303
|
+
benchmarking.source_stasher.vendor = true
|
|
304
|
+
else
|
|
305
|
+
# Default: Compare current_branch to master
|
|
306
|
+
# Optionally: pass in two refs as args to `bin/bench_regression`
|
|
307
|
+
# TODO: Consider checking across more revisions, to automatically find problems.
|
|
308
|
+
|
|
309
|
+
# super simple command line parsing
|
|
310
|
+
args = ARGV.dup
|
|
311
|
+
ref1 = args.shift
|
|
312
|
+
ref2 = args.shift
|
|
313
|
+
cmd = args
|
|
314
|
+
benchmarking.benchmark_refs(ref1: ref1, ref2: ref2, cmd: cmd)
|
|
315
|
+
end
|
|
316
|
+
end
|
data/bin/serve_benchmark
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
case "$1" in
|
|
5
|
+
|
|
6
|
+
start)
|
|
7
|
+
config="${CONFIG_RU:-test/benchmark/config.ru}"
|
|
8
|
+
bundle exec ruby -Ilib -S rackup "$config" --daemonize --pid tmp/benchmark_app.pid --warn --server webrick
|
|
9
|
+
until [ -f 'tmp/benchmark_app.pid' ]; do
|
|
10
|
+
sleep 0.1 # give it time to start.. I don't know a better way
|
|
11
|
+
done
|
|
12
|
+
cat tmp/benchmark_app.pid
|
|
13
|
+
true
|
|
14
|
+
;;
|
|
15
|
+
|
|
16
|
+
stop)
|
|
17
|
+
if [ -f 'tmp/benchmark_app.pid' ]; then
|
|
18
|
+
kill -TERM $(cat tmp/benchmark_app.pid)
|
|
19
|
+
else
|
|
20
|
+
echo 'No pidfile'
|
|
21
|
+
false
|
|
22
|
+
fi
|
|
23
|
+
;;
|
|
24
|
+
|
|
25
|
+
status)
|
|
26
|
+
if [ -f 'tmp/benchmark_app.pid' ]; then
|
|
27
|
+
kill -0 $(cat tmp/benchmark_app.pid)
|
|
28
|
+
[ "$?" -eq 0 ]
|
|
29
|
+
else
|
|
30
|
+
echo 'No pidfile'
|
|
31
|
+
false
|
|
32
|
+
fi
|
|
33
|
+
;;
|
|
34
|
+
|
|
35
|
+
*)
|
|
36
|
+
echo "Usage: $0 [start|stop|status]"
|
|
37
|
+
;;
|
|
38
|
+
|
|
39
|
+
esac
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
[Back to Guides](README.md)
|
|
2
|
+
|
|
3
|
+
This document focuses on architecture the 0.10.x version of ActiveModelSerializers. If you are interested in the architecture of the 0.8 or 0.9 versions,
|
|
4
|
+
please refer to the [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md) or
|
|
5
|
+
[0.9 README](https://github.com/rails-api/active_model_serializers/blob/0-9-stable/README.md).
|
|
6
|
+
|
|
7
|
+
The original design is also available [here](https://github.com/rails-api/active_model_serializers/blob/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e/README.textile).
|
|
8
|
+
|
|
9
|
+
# ARCHITECTURE
|
|
10
|
+
|
|
11
|
+
An **`ActiveModel::Serializer`** wraps a [serializable resource](https://github.com/rails/rails/blob/4-2-stable/activemodel/lib/active_model/serialization.rb)
|
|
12
|
+
and exposes an `attributes` method, among a few others.
|
|
13
|
+
It allows you to specify which attributes and associations should be represented in the serializatation of the resource.
|
|
14
|
+
It requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself.
|
|
15
|
+
It may be useful to think of it as a
|
|
16
|
+
[presenter](http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).
|
|
17
|
+
|
|
18
|
+
The **`ActiveModel::ArraySerializer`** represent a collection of resources as serializers
|
|
19
|
+
and, if there is no serializer, primitives.
|
|
20
|
+
|
|
21
|
+
The **`ActiveModel::Adapter`** describes the structure of the JSON document generated from a
|
|
22
|
+
serializer. For example, the `Attributes` example represents each serializer as its
|
|
23
|
+
unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
|
|
24
|
+
API](http://jsonapi.org/) document.
|
|
25
|
+
|
|
26
|
+
The **`ActiveModelSerializers::SerializableResource`** acts to coordinate the serializer(s) and adapter
|
|
27
|
+
to an object that responds to `to_json`, and `as_json`. It is used in the controller to
|
|
28
|
+
encapsulate the serialization resource when rendered. However, it can also be used on its own
|
|
29
|
+
to serialize a resource outside of a controller, as well.
|
|
30
|
+
|
|
31
|
+
## Primitive handling
|
|
32
|
+
|
|
33
|
+
Definitions: A primitive is usually a String or Array. There is no serializer
|
|
34
|
+
defined for them; they will be serialized when the resource is converted to JSON (`as_json` or
|
|
35
|
+
`to_json`). (The below also applies for any object with no serializer.)
|
|
36
|
+
|
|
37
|
+
ActiveModelSerializers doesn't handle primitives passed to `render json:` at all.
|
|
38
|
+
|
|
39
|
+
However, when a primitive value is an attribute or in a collection,
|
|
40
|
+
it is not modified.
|
|
41
|
+
|
|
42
|
+
Internally, if no serializer can be found in the controller, the resource is not decorated by
|
|
43
|
+
ActiveModelSerializers.
|
|
44
|
+
|
|
45
|
+
If the collection serializer (ArraySerializer) cannot
|
|
46
|
+
identify a serializer for a resource in its collection, it raises [`NoSerializerError`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128)
|
|
47
|
+
which is rescued in `ActiveModel::Serializer::Reflection#build_association` which sets
|
|
48
|
+
the association value directly:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
(which is called by the adapter as `serializer.associations(*)`.)
|
|
55
|
+
|
|
56
|
+
## How options are parsed
|
|
57
|
+
|
|
58
|
+
High-level overview:
|
|
59
|
+
|
|
60
|
+
- For a collection
|
|
61
|
+
- `:serializer` specifies the collection serializer and
|
|
62
|
+
- `:each_serializer` specifies the serializer for each resource in the collection.
|
|
63
|
+
- For a single resource, the `:serializer` option is the resource serializer.
|
|
64
|
+
- Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
|
|
65
|
+
[`ADAPTER_OPTION_KEYS`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/serializable_resource.rb#L5).
|
|
66
|
+
The remaining options are serializer options.
|
|
67
|
+
|
|
68
|
+
Details:
|
|
69
|
+
|
|
70
|
+
1. **ActionController::Serialization**
|
|
71
|
+
1. `serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)`
|
|
72
|
+
1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
|
|
73
|
+
The `adapter_opts` keys are defined in `ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS`.
|
|
74
|
+
1. **ActiveModelSerializers::SerializableResource**
|
|
75
|
+
1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
|
|
76
|
+
- Where `serializer?` is `use_adapter? && !!(serializer)`
|
|
77
|
+
- Where `use_adapter?`: 'True when no explicit adapter given, or explicit value is truthy (non-nil);
|
|
78
|
+
False when explicit adapter is falsy (nil or false)'
|
|
79
|
+
- Where `serializer`:
|
|
80
|
+
1. from explicit `:serializer` option, else
|
|
81
|
+
2. implicitly from resource `ActiveModel::Serializer.serializer_for(resource)`
|
|
82
|
+
1. A side-effect of checking `serializer` is:
|
|
83
|
+
- The `:serializer` option is removed from the serializer_opts hash
|
|
84
|
+
- If the `:each_serializer` option is present, it is removed from the serializer_opts hash and set as the `:serializer` option
|
|
85
|
+
1. The serializer and adapter are created as
|
|
86
|
+
1. `serializer_instance = serializer.new(resource, serializer_opts)`
|
|
87
|
+
2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
|
|
88
|
+
1. **ActiveModel::Serializer::ArraySerializer#new**
|
|
89
|
+
1. If the `serializer_instance` was a `ArraySerializer` and the `:serializer` serializer_opts
|
|
90
|
+
is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/a54d237e2828fe6bab1ea5dfe6360d4ecc8214cd/lib/active_model/serializer/array_serializer.rb#L14-L16).
|
|
91
|
+
1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
|
|
92
|
+
resource as defined by the serializer.
|
|
93
|
+
|
|
94
|
+
## What does a 'serializable resource' look like?
|
|
95
|
+
|
|
96
|
+
- An `ActiveRecord::Base` object.
|
|
97
|
+
- Any Ruby object that passes the
|
|
98
|
+
[Lint](http://www.rubydoc.info/github/rails-api/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
|
|
99
|
+
[code](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/lint.rb).
|
|
100
|
+
|
|
101
|
+
ActiveModelSerializers provides a
|
|
102
|
+
[`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb),
|
|
103
|
+
which is a simple serializable PORO (Plain-Old Ruby Object).
|
|
104
|
+
|
|
105
|
+
ActiveModelSerializers::Model may be used either as a template, or in production code.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
class MyModel < ActiveModelSerializers::Model
|
|
109
|
+
attr_accessor :id, :name, :level
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The default serializer for `MyModel` would be `MyModelSerializer` whether MyModel is an
|
|
114
|
+
ActiveRecord::Base object or not.
|
|
115
|
+
|
|
116
|
+
Outside of the controller the rules are **exactly** the same as for records. For example:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
render json: MyModel.new(level: 'awesome'), adapter: :json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
would be serialized the same as
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
|
|
126
|
+
```
|
data/docs/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Docs - ActiveModel::Serializer 0.10.x
|
|
2
|
+
|
|
3
|
+
This is the documentation of ActiveModelSerializers, it's focused on the **0.10.x version.**
|
|
4
|
+
|
|
5
|
+
-----
|
|
6
|
+
|
|
7
|
+
## General
|
|
8
|
+
|
|
9
|
+
- [Getting Started](general/getting_started.md)
|
|
10
|
+
- [Configuration Options](general/configuration_options.md)
|
|
11
|
+
- [Serializers](general/serializers.md)
|
|
12
|
+
- [Adapters](general/adapters.md)
|
|
13
|
+
- [Rendering](general/rendering.md)
|
|
14
|
+
- [Caching](general/caching.md)
|
|
15
|
+
- [Logging](general/logging.md)
|
|
16
|
+
- [Deserialization](general/deserialization.md)
|
|
17
|
+
- [Instrumentation](general/instrumentation.md)
|
|
18
|
+
- JSON API
|
|
19
|
+
- [Schema](jsonapi/schema.md)
|
|
20
|
+
- [Errors](jsonapi/errors.md)
|
|
21
|
+
- [ARCHITECTURE](ARCHITECTURE.md)
|
|
22
|
+
|
|
23
|
+
## How to
|
|
24
|
+
|
|
25
|
+
- [How to add root key](howto/add_root_key.md)
|
|
26
|
+
- [How to add pagination links](howto/add_pagination_links.md)
|
|
27
|
+
- [Using ActiveModelSerializers Outside Of Controllers](howto/outside_controller_use.md)
|
|
28
|
+
- [Testing ActiveModelSerializers](howto/test.md)
|
|
29
|
+
- [Passing Arbitrary Options](howto/passing_arbitrary_options.md)
|
|
30
|
+
- [How to serialize a Plain-Old Ruby Object (PORO)](howto/serialize_poro.md)
|
|
31
|
+
|
|
32
|
+
## Integrations
|
|
33
|
+
|
|
34
|
+
| Integration | Supported ActiveModelSerializers versions | Gem name and/or link
|
|
35
|
+
|----|-----|----
|
|
36
|
+
| Ember.js | 0.9.x | [active-model-adapter](https://github.com/ember-data/active-model-adapter)
|
|
37
|
+
| Ember.js | 0.10.x + | [docs/integrations/ember-and-json-api.md](integrations/ember-and-json-api.md)
|
|
38
|
+
| Grape | 0.10.x + | [docs/integrations/grape.md](integrations/grape.md) |
|
|
39
|
+
| Grape | 0.9.x | https://github.com/jrhe/grape-active_model_serializers/ |
|
|
40
|
+
| Sinatra | 0.9.x | https://github.com/SauloSilva/sinatra-active-model-serializers/
|
data/docs/STYLE.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# STYLE
|
|
2
|
+
|
|
3
|
+
## Code and comments
|
|
4
|
+
|
|
5
|
+
- We are actively working to identify tasks under the label [**Good for New
|
|
6
|
+
Contributors**](https://github.com/rails-api/active_model_serializers/labels/Good%20for%20New%20Contributors).
|
|
7
|
+
- [Changelog
|
|
8
|
+
Missing](https://github.com/rails-api/active_model_serializers/issues?q=label%3A%22Changelog+Missing%22+is%3Aclosed) is
|
|
9
|
+
an easy way to help out.
|
|
10
|
+
|
|
11
|
+
- [Fix a bug](https://github.com/rails-api/active_model_serializers/labels/Ready%20for%20PR).
|
|
12
|
+
- Ready for PR - A well defined bug, needs someone to PR a fix.
|
|
13
|
+
- Bug - Anything that is broken.
|
|
14
|
+
- Regression - A bug that did not exist in previous versions and isn't a new feature (applied in tandem with Bug).
|
|
15
|
+
- Performance - A performance related issue. We could track this as a bug, but usually these would have slightly lower priority than standard bugs.
|
|
16
|
+
|
|
17
|
+
- [Develop new features](https://github.com/rails-api/active_model_serializers/labels/Feature).
|
|
18
|
+
|
|
19
|
+
- [Improve code quality](https://codeclimate.com/github/rails-api/active_model_serializers/code?sort=smell_count&sort_direction=desc).
|
|
20
|
+
|
|
21
|
+
- [Improve amount of code exercised by tests](https://codeclimate.com/github/rails-api/active_model_serializers/coverage?sort=covered_percent&sort_direction=asc).
|
|
22
|
+
|
|
23
|
+
- [Fix RuboCop (Style) TODOS](https://github.com/rails-api/active_model_serializers/blob/master/.rubocop_todo.yml).
|
|
24
|
+
- Delete and offsense, run `rake rubocop` (or possibly `rake rubocop:auto_correct`),
|
|
25
|
+
and [submit a PR](CONTRIBUTING.md#submitting-a-pull-request-pr).
|
|
26
|
+
|
|
27
|
+
- We are also encouraging comments to substantial changes (larger than bugfixes and simple features) under an
|
|
28
|
+
"RFC" (Request for Comments) process before we start active development.
|
|
29
|
+
Look for the [**RFC**](https://github.com/rails-api/active_model_serializers/labels/RFC) label.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Pull requests
|
|
33
|
+
|
|
34
|
+
- If the tests pass and the pull request looks good, a maintainer will merge it.
|
|
35
|
+
- If the pull request needs to be changed,
|
|
36
|
+
- you can change it by updating the branch you generated the pull request from
|
|
37
|
+
- either by adding more commits, or
|
|
38
|
+
- by force pushing to it
|
|
39
|
+
- A maintainer can make any changes themselves and manually merge the code in.
|
|
40
|
+
|
|
41
|
+
## Commit messages
|
|
42
|
+
|
|
43
|
+
- [A Note About Git Commit Messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
|
44
|
+
- [http://stopwritingramblingcommitmessages.com/](http://stopwritingramblingcommitmessages.com/)
|
|
45
|
+
- [ThoughtBot style guide](https://github.com/thoughtbot/guides/tree/master/style#git)
|
|
46
|
+
|
|
47
|
+
#### About Pull Requests (PR's)
|
|
48
|
+
|
|
49
|
+
- [Using Pull Requests](https://help.github.com/articles/using-pull-requests)
|
|
50
|
+
- [Github pull requests made easy](http://www.element84.com/github-pull-requests-made-easy.html)
|
|
51
|
+
- [Exercism Git Workflow](http://help.exercism.io/git-workflow.html).
|
|
52
|
+
- [Level up your Git](http://rakeroutes.com/blog/deliberate-git/)
|
|
53
|
+
- [All Your Open Source Code Are Belong To Us](http://www.benjaminfleischer.com/2013/07/30/all-your-open-source-code-are-belong-to-us/)
|
|
54
|
+
|
|
55
|
+
## Issue Labeling
|
|
56
|
+
|
|
57
|
+
ActiveModelSerializers uses a subset of [StandardIssueLabels](https://github.com/wagenet/StandardIssueLabels) for Github Issues. You can [see our labels here](https://github.com/rails-api/active_model_serializers/labels).
|
|
58
|
+
|