active_model_serializers 0.10.3 → 0.10.12

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 (224) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +154 -2
  3. data/README.md +153 -15
  4. data/lib/action_controller/serialization.rb +11 -1
  5. data/lib/active_model/serializable_resource.rb +2 -0
  6. data/lib/active_model/serializer.rb +275 -81
  7. data/lib/active_model/serializer/adapter.rb +2 -0
  8. data/lib/active_model/serializer/adapter/attributes.rb +2 -0
  9. data/lib/active_model/serializer/adapter/base.rb +2 -0
  10. data/lib/active_model/serializer/adapter/json.rb +2 -0
  11. data/lib/active_model/serializer/adapter/json_api.rb +2 -0
  12. data/lib/active_model/serializer/adapter/null.rb +2 -0
  13. data/lib/active_model/serializer/array_serializer.rb +2 -0
  14. data/lib/active_model/serializer/association.rb +53 -14
  15. data/lib/active_model/serializer/attribute.rb +2 -0
  16. data/lib/active_model/serializer/belongs_to_reflection.rb +7 -1
  17. data/lib/active_model/serializer/collection_serializer.rb +8 -5
  18. data/lib/active_model/serializer/concerns/caching.rb +36 -23
  19. data/lib/active_model/serializer/error_serializer.rb +2 -0
  20. data/lib/active_model/serializer/errors_serializer.rb +2 -0
  21. data/lib/active_model/serializer/field.rb +2 -0
  22. data/lib/active_model/serializer/fieldset.rb +3 -1
  23. data/lib/active_model/serializer/has_many_reflection.rb +6 -1
  24. data/lib/active_model/serializer/has_one_reflection.rb +3 -1
  25. data/lib/active_model/serializer/lazy_association.rb +99 -0
  26. data/lib/active_model/serializer/link.rb +23 -0
  27. data/lib/active_model/serializer/lint.rb +2 -0
  28. data/lib/active_model/serializer/null.rb +2 -0
  29. data/lib/active_model/serializer/reflection.rb +122 -73
  30. data/lib/active_model/serializer/version.rb +3 -1
  31. data/lib/active_model_serializers.rb +29 -11
  32. data/lib/active_model_serializers/adapter.rb +3 -1
  33. data/lib/active_model_serializers/adapter/attributes.rb +23 -0
  34. data/lib/active_model_serializers/adapter/base.rb +4 -2
  35. data/lib/active_model_serializers/adapter/json.rb +2 -0
  36. data/lib/active_model_serializers/adapter/json_api.rb +44 -26
  37. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +4 -2
  38. data/lib/active_model_serializers/adapter/json_api/error.rb +2 -0
  39. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +2 -0
  40. data/lib/active_model_serializers/adapter/json_api/link.rb +2 -0
  41. data/lib/active_model_serializers/adapter/json_api/meta.rb +2 -0
  42. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +42 -21
  43. data/lib/active_model_serializers/adapter/json_api/relationship.rb +52 -9
  44. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +35 -18
  45. data/lib/active_model_serializers/adapter/null.rb +2 -0
  46. data/lib/active_model_serializers/callbacks.rb +2 -0
  47. data/lib/active_model_serializers/deprecate.rb +2 -0
  48. data/lib/active_model_serializers/deserialization.rb +2 -0
  49. data/lib/active_model_serializers/json_pointer.rb +2 -0
  50. data/lib/active_model_serializers/logging.rb +2 -0
  51. data/lib/active_model_serializers/lookup_chain.rb +2 -0
  52. data/lib/active_model_serializers/model.rb +111 -30
  53. data/lib/active_model_serializers/model/caching.rb +25 -0
  54. data/lib/active_model_serializers/railtie.rb +4 -0
  55. data/lib/active_model_serializers/register_jsonapi_renderer.rb +2 -0
  56. data/lib/active_model_serializers/serializable_resource.rb +4 -2
  57. data/lib/active_model_serializers/serialization_context.rb +2 -0
  58. data/lib/active_model_serializers/test.rb +2 -0
  59. data/lib/active_model_serializers/test/schema.rb +4 -2
  60. data/lib/active_model_serializers/test/serializer.rb +2 -0
  61. data/lib/generators/rails/resource_override.rb +3 -1
  62. data/lib/generators/rails/serializer_generator.rb +2 -0
  63. data/lib/grape/active_model_serializers.rb +2 -0
  64. data/lib/grape/formatters/active_model_serializers.rb +2 -0
  65. data/lib/grape/helpers/active_model_serializers.rb +2 -0
  66. data/lib/tasks/rubocop.rake +55 -0
  67. metadata +74 -291
  68. data/.github/ISSUE_TEMPLATE.md +0 -29
  69. data/.github/PULL_REQUEST_TEMPLATE.md +0 -15
  70. data/.gitignore +0 -35
  71. data/.rubocop.yml +0 -102
  72. data/.simplecov +0 -110
  73. data/.travis.yml +0 -51
  74. data/CODE_OF_CONDUCT.md +0 -74
  75. data/CONTRIBUTING.md +0 -105
  76. data/Gemfile +0 -56
  77. data/Rakefile +0 -103
  78. data/active_model_serializers.gemspec +0 -62
  79. data/appveyor.yml +0 -24
  80. data/bin/bench +0 -171
  81. data/bin/bench_regression +0 -316
  82. data/bin/serve_benchmark +0 -39
  83. data/docs/ARCHITECTURE.md +0 -125
  84. data/docs/README.md +0 -42
  85. data/docs/STYLE.md +0 -58
  86. data/docs/general/adapters.md +0 -247
  87. data/docs/general/caching.md +0 -58
  88. data/docs/general/configuration_options.md +0 -169
  89. data/docs/general/deserialization.md +0 -100
  90. data/docs/general/fields.md +0 -31
  91. data/docs/general/getting_started.md +0 -133
  92. data/docs/general/instrumentation.md +0 -40
  93. data/docs/general/key_transforms.md +0 -40
  94. data/docs/general/logging.md +0 -14
  95. data/docs/general/rendering.md +0 -294
  96. data/docs/general/serializers.md +0 -461
  97. data/docs/how-open-source-maintained.jpg +0 -0
  98. data/docs/howto/add_pagination_links.md +0 -138
  99. data/docs/howto/add_relationship_links.md +0 -137
  100. data/docs/howto/add_root_key.md +0 -55
  101. data/docs/howto/grape_integration.md +0 -42
  102. data/docs/howto/outside_controller_use.md +0 -65
  103. data/docs/howto/passing_arbitrary_options.md +0 -27
  104. data/docs/howto/serialize_poro.md +0 -32
  105. data/docs/howto/test.md +0 -154
  106. data/docs/howto/upgrade_from_0_8_to_0_10.md +0 -265
  107. data/docs/integrations/ember-and-json-api.md +0 -144
  108. data/docs/integrations/grape.md +0 -19
  109. data/docs/jsonapi/errors.md +0 -56
  110. data/docs/jsonapi/schema.md +0 -151
  111. data/docs/jsonapi/schema/schema.json +0 -366
  112. data/docs/rfcs/0000-namespace.md +0 -106
  113. data/docs/rfcs/template.md +0 -15
  114. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  115. data/lib/active_model/serializer/concerns/associations.rb +0 -102
  116. data/lib/active_model/serializer/concerns/attributes.rb +0 -82
  117. data/lib/active_model/serializer/concerns/configuration.rb +0 -59
  118. data/lib/active_model/serializer/concerns/links.rb +0 -35
  119. data/lib/active_model/serializer/concerns/meta.rb +0 -29
  120. data/lib/active_model/serializer/concerns/type.rb +0 -25
  121. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  122. data/lib/active_model_serializers/key_transform.rb +0 -74
  123. data/test/action_controller/adapter_selector_test.rb +0 -53
  124. data/test/action_controller/explicit_serializer_test.rb +0 -135
  125. data/test/action_controller/json/include_test.rb +0 -246
  126. data/test/action_controller/json_api/deserialization_test.rb +0 -112
  127. data/test/action_controller/json_api/errors_test.rb +0 -40
  128. data/test/action_controller/json_api/fields_test.rb +0 -57
  129. data/test/action_controller/json_api/linked_test.rb +0 -202
  130. data/test/action_controller/json_api/pagination_test.rb +0 -116
  131. data/test/action_controller/json_api/transform_test.rb +0 -181
  132. data/test/action_controller/lookup_proc_test.rb +0 -49
  133. data/test/action_controller/namespace_lookup_test.rb +0 -226
  134. data/test/action_controller/serialization_scope_name_test.rb +0 -229
  135. data/test/action_controller/serialization_test.rb +0 -472
  136. data/test/active_model_serializers/adapter_for_test.rb +0 -208
  137. data/test/active_model_serializers/json_pointer_test.rb +0 -22
  138. data/test/active_model_serializers/key_transform_test.rb +0 -297
  139. data/test/active_model_serializers/logging_test.rb +0 -77
  140. data/test/active_model_serializers/model_test.rb +0 -22
  141. data/test/active_model_serializers/railtie_test_isolated.rb +0 -63
  142. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +0 -143
  143. data/test/active_model_serializers/serialization_context_test_isolated.rb +0 -71
  144. data/test/active_model_serializers/test/schema_test.rb +0 -130
  145. data/test/active_model_serializers/test/serializer_test.rb +0 -62
  146. data/test/active_record_test.rb +0 -9
  147. data/test/adapter/attributes_test.rb +0 -43
  148. data/test/adapter/deprecation_test.rb +0 -100
  149. data/test/adapter/json/belongs_to_test.rb +0 -45
  150. data/test/adapter/json/collection_test.rb +0 -104
  151. data/test/adapter/json/has_many_test.rb +0 -45
  152. data/test/adapter/json/transform_test.rb +0 -93
  153. data/test/adapter/json_api/belongs_to_test.rb +0 -155
  154. data/test/adapter/json_api/collection_test.rb +0 -96
  155. data/test/adapter/json_api/errors_test.rb +0 -76
  156. data/test/adapter/json_api/fields_test.rb +0 -88
  157. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  158. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +0 -96
  159. data/test/adapter/json_api/has_many_test.rb +0 -165
  160. data/test/adapter/json_api/has_one_test.rb +0 -80
  161. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +0 -166
  162. data/test/adapter/json_api/json_api_test.rb +0 -33
  163. data/test/adapter/json_api/linked_test.rb +0 -413
  164. data/test/adapter/json_api/links_test.rb +0 -95
  165. data/test/adapter/json_api/pagination_links_test.rb +0 -193
  166. data/test/adapter/json_api/parse_test.rb +0 -137
  167. data/test/adapter/json_api/relationship_test.rb +0 -397
  168. data/test/adapter/json_api/resource_identifier_test.rb +0 -110
  169. data/test/adapter/json_api/resource_meta_test.rb +0 -100
  170. data/test/adapter/json_api/toplevel_jsonapi_test.rb +0 -82
  171. data/test/adapter/json_api/transform_test.rb +0 -504
  172. data/test/adapter/json_api/type_test.rb +0 -61
  173. data/test/adapter/json_test.rb +0 -46
  174. data/test/adapter/null_test.rb +0 -22
  175. data/test/adapter/polymorphic_test.rb +0 -171
  176. data/test/adapter_test.rb +0 -67
  177. data/test/array_serializer_test.rb +0 -22
  178. data/test/benchmark/app.rb +0 -65
  179. data/test/benchmark/benchmarking_support.rb +0 -67
  180. data/test/benchmark/bm_active_record.rb +0 -81
  181. data/test/benchmark/bm_adapter.rb +0 -38
  182. data/test/benchmark/bm_caching.rb +0 -119
  183. data/test/benchmark/bm_lookup_chain.rb +0 -83
  184. data/test/benchmark/bm_transform.rb +0 -45
  185. data/test/benchmark/config.ru +0 -3
  186. data/test/benchmark/controllers.rb +0 -83
  187. data/test/benchmark/fixtures.rb +0 -219
  188. data/test/cache_test.rb +0 -579
  189. data/test/collection_serializer_test.rb +0 -110
  190. data/test/fixtures/active_record.rb +0 -78
  191. data/test/fixtures/poro.rb +0 -286
  192. data/test/generators/scaffold_controller_generator_test.rb +0 -24
  193. data/test/generators/serializer_generator_test.rb +0 -74
  194. data/test/grape_test.rb +0 -178
  195. data/test/lint_test.rb +0 -49
  196. data/test/logger_test.rb +0 -20
  197. data/test/poro_test.rb +0 -9
  198. data/test/serializable_resource_test.rb +0 -79
  199. data/test/serializers/association_macros_test.rb +0 -37
  200. data/test/serializers/associations_test.rb +0 -370
  201. data/test/serializers/attribute_test.rb +0 -151
  202. data/test/serializers/attributes_test.rb +0 -52
  203. data/test/serializers/caching_configuration_test_isolated.rb +0 -170
  204. data/test/serializers/configuration_test.rb +0 -32
  205. data/test/serializers/fieldset_test.rb +0 -14
  206. data/test/serializers/meta_test.rb +0 -202
  207. data/test/serializers/options_test.rb +0 -21
  208. data/test/serializers/read_attribute_for_serialization_test.rb +0 -79
  209. data/test/serializers/root_test.rb +0 -21
  210. data/test/serializers/serialization_test.rb +0 -55
  211. data/test/serializers/serializer_for_test.rb +0 -136
  212. data/test/serializers/serializer_for_with_namespace_test.rb +0 -87
  213. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  214. data/test/support/isolated_unit.rb +0 -82
  215. data/test/support/rails5_shims.rb +0 -53
  216. data/test/support/rails_app.rb +0 -36
  217. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  218. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +0 -6
  219. data/test/support/schemas/custom/show.json +0 -7
  220. data/test/support/schemas/hyper_schema.json +0 -93
  221. data/test/support/schemas/render_using_json_api.json +0 -43
  222. data/test/support/schemas/simple_json_pointers.json +0 -10
  223. data/test/support/serialization_testing.rb +0 -71
  224. data/test/test_helper.rb +0 -58
data/Gemfile DELETED
@@ -1,56 +0,0 @@
1
- source 'https://rubygems.org'
2
- #
3
- # Add a Gemfile.local to locally bundle gems outside of version control
4
- local_gemfile = File.join(File.expand_path('..', __FILE__), 'Gemfile.local')
5
- eval_gemfile local_gemfile if File.readable?(local_gemfile)
6
-
7
- # Specify your gem's dependencies in active_model_serializers.gemspec
8
- gemspec
9
-
10
- version = ENV['RAILS_VERSION'] || '4.2'
11
-
12
- if version == 'master'
13
- gem 'rack', github: 'rack/rack'
14
- gem 'arel', github: 'rails/arel'
15
- git 'https://github.com/rails/rails.git' do
16
- gem 'railties'
17
- gem 'activesupport'
18
- gem 'activemodel'
19
- gem 'actionpack'
20
- gem 'activerecord', group: :test
21
- # Rails 5
22
- gem 'actionview'
23
- end
24
- else
25
- gem_version = "~> #{version}.0"
26
- gem 'railties', gem_version
27
- gem 'activesupport', gem_version
28
- gem 'activemodel', gem_version
29
- gem 'actionpack', gem_version
30
- gem 'activerecord', gem_version, group: :test
31
- end
32
-
33
- # https://github.com/bundler/bundler/blob/89a8778c19269561926cea172acdcda241d26d23/lib/bundler/dependency.rb#L30-L54
34
- @windows_platforms = [:mswin, :mingw, :x64_mingw]
35
-
36
- # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
37
- gem 'tzinfo-data', platforms: (@windows_platforms + [:jruby])
38
-
39
- group :bench do
40
- # https://github.com/rails-api/active_model_serializers/commit/cb4459580a6f4f37f629bf3185a5224c8624ca76
41
- gem 'benchmark-ips', '>= 2.7.2', require: false, group: :development
42
- end
43
-
44
- group :test do
45
- gem 'sqlite3', platform: (@windows_platforms + [:ruby])
46
- gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
47
- gem 'codeclimate-test-reporter', require: false
48
- gem 'm', '~> 1.5'
49
- gem 'pry', '~> 0.10'
50
- gem 'pry-byebug', '~> 3.4', platform: :ruby
51
- end
52
-
53
- group :development, :test do
54
- gem 'rubocop', '~> 0.40.0', require: false
55
- gem 'yard', require: false
56
- end
data/Rakefile DELETED
@@ -1,103 +0,0 @@
1
- begin
2
- require 'bundler/setup'
3
- rescue LoadError
4
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
- end
6
- begin
7
- require 'simplecov'
8
- rescue LoadError # rubocop:disable Lint/HandleExceptions
9
- end
10
-
11
- Bundler::GemHelper.install_tasks
12
-
13
- require 'yard'
14
-
15
- namespace :yard do
16
- YARD::Rake::YardocTask.new(:doc) do |t|
17
- t.stats_options = ['--list-undoc']
18
- end
19
-
20
- desc 'start a gem server'
21
- task :server do
22
- sh 'bundle exec yard server --gems'
23
- end
24
-
25
- desc 'use Graphviz to generate dot graph'
26
- task :graph do
27
- output_file = 'doc/erd.dot'
28
- sh "bundle exec yard graph --protected --full --dependencies > #{output_file}"
29
- puts 'open doc/erd.dot if you have graphviz installed'
30
- end
31
- end
32
-
33
- begin
34
- require 'rubocop'
35
- require 'rubocop/rake_task'
36
- rescue LoadError # rubocop:disable Lint/HandleExceptions
37
- else
38
- Rake::Task[:rubocop].clear if Rake::Task.task_defined?(:rubocop)
39
- require 'rbconfig'
40
- # https://github.com/bundler/bundler/blob/1b3eb2465a/lib/bundler/constants.rb#L2
41
- windows_platforms = /(msdos|mswin|djgpp|mingw)/
42
- if RbConfig::CONFIG['host_os'] =~ windows_platforms
43
- desc 'No-op rubocop on Windows-- unsupported platform'
44
- task :rubocop do
45
- puts 'Skipping rubocop on Windows'
46
- end
47
- elsif defined?(::Rubinius)
48
- desc 'No-op rubocop to avoid rbx segfault'
49
- task :rubocop do
50
- puts 'Skipping rubocop on rbx due to segfault'
51
- puts 'https://github.com/rubinius/rubinius/issues/3499'
52
- end
53
- else
54
- Rake::Task[:rubocop].clear if Rake::Task.task_defined?(:rubocop)
55
- desc 'Execute rubocop'
56
- RuboCop::RakeTask.new(:rubocop) do |task|
57
- task.options = ['--rails', '--display-cop-names', '--display-style-guide']
58
- task.fail_on_error = true
59
- end
60
- end
61
- end
62
-
63
- require 'rake/testtask'
64
-
65
- Rake::TestTask.new(:test) do |t|
66
- t.libs << 'lib'
67
- t.libs << 'test'
68
- t.pattern = 'test/**/*_test.rb'
69
- t.ruby_opts = ['-r./test/test_helper.rb']
70
- t.ruby_opts << ' -w' unless ENV['NO_WARN'] == 'true'
71
- t.verbose = true
72
- end
73
-
74
- desc 'Run isolated tests'
75
- task isolated: ['test:isolated']
76
- namespace :test do
77
- task :isolated do
78
- desc 'Run isolated tests for Railtie'
79
- require 'shellwords'
80
- dir = File.dirname(__FILE__)
81
- dir = Shellwords.shellescape(dir)
82
- isolated_test_files = FileList['test/**/*_test_isolated.rb']
83
- # https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
84
- _bundle_command = Gem.bin_path('bundler', 'bundle')
85
- require 'bundler'
86
- Bundler.with_clean_env do
87
- isolated_test_files.all? do |test_file|
88
- command = "-w -I#{dir}/lib -I#{dir}/test #{Shellwords.shellescape(test_file)}"
89
- full_command = %("#{Gem.ruby}" #{command})
90
- system(full_command)
91
- end or fail 'Failures' # rubocop:disable Style/AndOr
92
- end
93
- end
94
- end
95
-
96
- if ENV['RAILS_VERSION'].to_s > '4.0' && RUBY_ENGINE == 'ruby'
97
- task default: [:isolated, :test, :rubocop]
98
- else
99
- task default: [:test, :rubocop]
100
- end
101
-
102
- desc 'CI test task'
103
- task ci: [:default]
@@ -1,62 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'active_model/serializer/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = 'active_model_serializers'
8
- spec.version = ActiveModel::Serializer::VERSION
9
- spec.platform = Gem::Platform::RUBY
10
- spec.authors = ['Steve Klabnik']
11
- spec.email = ['steve@steveklabnik.com']
12
- spec.summary = 'Conventions-based JSON generation for Rails.'
13
- spec.description = 'ActiveModel::Serializers allows you to generate your JSON in an object-oriented and convention-driven manner.'
14
- spec.homepage = 'https://github.com/rails-api/active_model_serializers'
15
- spec.license = 'MIT'
16
-
17
- spec.files = `git ls-files -z`.split("\x0")
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ['lib']
20
- spec.executables = []
21
-
22
- spec.required_ruby_version = '>= 2.1'
23
-
24
- rails_versions = ['>= 4.1', '< 6']
25
- spec.add_runtime_dependency 'activemodel', rails_versions
26
- # 'activesupport', rails_versions
27
- # 'builder'
28
-
29
- spec.add_runtime_dependency 'actionpack', rails_versions
30
- # 'activesupport', rails_versions
31
- # 'rack'
32
- # 'rack-test', '~> 0.6.2'
33
-
34
- spec.add_development_dependency 'railties', rails_versions
35
- # 'activesupport', rails_versions
36
- # 'actionpack', rails_versions
37
- # 'rake', '>= 0.8.7'
38
-
39
- # 'activesupport', rails_versions
40
- # 'i18n,
41
- # 'tzinfo'
42
- # 'minitest'
43
- # 'thread_safe'
44
-
45
- spec.add_runtime_dependency 'jsonapi', '0.1.1.beta2'
46
-
47
- spec.add_development_dependency 'activerecord', rails_versions
48
- # arel
49
- # activesupport
50
- # activemodel
51
-
52
- # Soft dependency for pagination
53
- spec.add_development_dependency 'kaminari', ' ~> 0.16.3'
54
- spec.add_development_dependency 'will_paginate', '~> 3.0', '>= 3.0.7'
55
-
56
- spec.add_development_dependency 'bundler', '~> 1.6'
57
- spec.add_development_dependency 'simplecov', '~> 0.11'
58
- spec.add_development_dependency 'timecop', '~> 0.7'
59
- spec.add_development_dependency 'grape', ['>= 0.13', '< 1.0']
60
- spec.add_development_dependency 'json_schema'
61
- spec.add_development_dependency 'rake', ['>= 10.0', '< 12.0']
62
- end
data/appveyor.yml DELETED
@@ -1,24 +0,0 @@
1
- version: '{build}'
2
-
3
- skip_tags: true
4
-
5
- environment:
6
- JRUBY_OPTS: "--dev -J-Xmx1024M --debug"
7
- matrix:
8
- - ruby_version: "Ruby21"
9
- - ruby_version: "Ruby21-x64"
10
- - ruby_version: "jruby-9.0.0.0"
11
-
12
- cache:
13
- - vendor/bundle
14
-
15
- install:
16
- - SET PATH=C:\%ruby_version%\bin;%PATH%
17
- - gem install bundler
18
- - bundle env
19
- - bundle install --path=vendor/bundle --retry=3 --jobs=3
20
-
21
- test_script:
22
- - bundle exec rake ci
23
-
24
- build: off
data/bin/bench DELETED
@@ -1,171 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # ActiveModelSerializers Benchmark driver
3
- # Adapted from
4
- # https://github.com/ruby-bench/ruby-bench-suite/blob/8ad567f7e43a044ae48c36833218423bb1e2bd9d/rails/benchmarks/driver.rb
5
- require 'bundler'
6
- Bundler.setup
7
- require 'json'
8
- require 'pathname'
9
- require 'optparse'
10
- require 'digest'
11
- require 'pathname'
12
- require 'shellwords'
13
- require 'logger'
14
- require 'English'
15
-
16
- class BenchmarkDriver
17
- ROOT = Pathname File.expand_path(File.join('..', '..'), __FILE__)
18
- BASE = ENV.fetch('BASE') { ROOT.join('test', 'benchmark') }
19
- ESCAPED_BASE = Shellwords.shellescape(BASE)
20
-
21
- def self.benchmark(options)
22
- new(options).run
23
- end
24
-
25
- def self.parse_argv_and_run(argv = ARGV, options = {})
26
- options = {
27
- repeat_count: 1,
28
- pattern: [],
29
- env: 'CACHE_ON=on'
30
- }.merge!(options)
31
-
32
- OptionParser.new do |opts|
33
- opts.banner = 'Usage: bin/bench [options]'
34
-
35
- opts.on('-r', '--repeat-count [NUM]', 'Run benchmarks [NUM] times taking the best result') do |value|
36
- options[:repeat_count] = value.to_i
37
- end
38
-
39
- opts.on('-p', '--pattern <PATTERN1,PATTERN2,PATTERN3>', 'Benchmark name pattern') do |value|
40
- options[:pattern] = value.split(',')
41
- end
42
-
43
- opts.on('-e', '--env <var1=val1,var2=val2,var3=vale>', 'ENV variables to pass in') do |value|
44
- options[:env] = value.split(',')
45
- end
46
- end.parse!(argv)
47
-
48
- benchmark(options)
49
- end
50
-
51
- attr_reader :commit_hash, :base
52
-
53
- # Based on logfmt:
54
- # https://www.brandur.org/logfmt
55
- # For more complete implementation see:
56
- # see https://github.com/arachnid-cb/logfmtr/blob/master/lib/logfmtr/base.rb
57
- # For usage see:
58
- # https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write/
59
- # https://engineering.heroku.com/blogs/2014-09-05-hutils-explore-your-structured-data-logs/
60
- # For Ruby parser see:
61
- # https://github.com/cyberdelia/logfmt-ruby
62
- def self.summary_logger(device = 'output.txt')
63
- require 'time'
64
- logger = Logger.new(device)
65
- logger.level = Logger::INFO
66
- logger.formatter = proc { |severity, datetime, progname, msg|
67
- msg = "'#{msg}'"
68
- "level=#{severity} time=#{datetime.utc.iso8601(6)} pid=#{Process.pid} progname=#{progname} msg=#{msg}#{$INPUT_RECORD_SEPARATOR}"
69
- }
70
- logger
71
- end
72
-
73
- def self.stdout_logger
74
- logger = Logger.new(STDOUT)
75
- logger.level = Logger::INFO
76
- logger.formatter = proc { |_, _, _, msg| "#{msg}#{$INPUT_RECORD_SEPARATOR}" }
77
- logger
78
- end
79
-
80
- def initialize(options)
81
- @writer = ENV['SUMMARIZE'] ? self.class.summary_logger : self.class.stdout_logger
82
- @repeat_count = options[:repeat_count]
83
- @pattern = options[:pattern]
84
- @commit_hash = options.fetch(:commit_hash) { `git rev-parse --short HEAD`.chomp }
85
- @base = options.fetch(:base) { ESCAPED_BASE }
86
- @env = Array(options[:env]).join(' ')
87
- @rubyopt = options[:rubyopt] # TODO: rename
88
- end
89
-
90
- def run
91
- files.each do |path|
92
- next if !@pattern.empty? && /#{@pattern.join('|')}/ !~ File.basename(path)
93
- run_single(Shellwords.shellescape(path))
94
- end
95
- end
96
-
97
- private
98
-
99
- def files
100
- Dir[File.join(base, 'bm_*')]
101
- end
102
-
103
- def run_single(path)
104
- script = "RAILS_ENV=production #{@env} ruby #{@rubyopt} #{path}"
105
- environment = `ruby -v`.chomp.strip[/\d+\.\d+\.\d+\w+/]
106
-
107
- runs_output = measure(script)
108
- if runs_output.empty?
109
- results = { error: :no_results }
110
- return
111
- end
112
-
113
- results = {}
114
- results['commit_hash'] = commit_hash
115
- results['version'] = runs_output.first['version']
116
- results['rails_version'] = runs_output.first['rails_version']
117
- results['benchmark_run[environment]'] = environment
118
- results['runs'] = []
119
-
120
- runs_output.each do |output|
121
- results['runs'] << {
122
- 'benchmark_type[category]' => output['label'],
123
- 'benchmark_run[result][iterations_per_second]' => output['iterations_per_second'].round(3),
124
- 'benchmark_run[result][total_allocated_objects_per_iteration]' => output['total_allocated_objects_per_iteration']
125
- }
126
- end
127
- ensure
128
- results && report(results)
129
- end
130
-
131
- def report(results)
132
- @writer.info { 'Benchmark results:' }
133
- @writer.info { JSON.pretty_generate(results) }
134
- end
135
-
136
- def summarize(result)
137
- puts "#{result['label']} #{result['iterations_per_second']}/ips; #{result['total_allocated_objects_per_iteration']} objects"
138
- end
139
-
140
- # FIXME: ` provides the full output but it'll return failed output as well.
141
- def measure(script)
142
- results = Hash.new { |h, k| h[k] = [] }
143
-
144
- @repeat_count.times do
145
- output = sh(script)
146
- output.each_line do |line|
147
- next if line.nil?
148
- begin
149
- result = JSON.parse(line)
150
- rescue JSON::ParserError
151
- result = { error: line } # rubocop:disable Lint/UselessAssignment
152
- else
153
- summarize(result)
154
- results[result['label']] << result
155
- end
156
- end
157
- end
158
-
159
- results.map do |_, bm_runs|
160
- bm_runs.sort_by do |run|
161
- run['iterations_per_second']
162
- end.last
163
- end
164
- end
165
-
166
- def sh(cmd)
167
- `#{cmd}`
168
- end
169
- end
170
-
171
- BenchmarkDriver.parse_argv_and_run if $PROGRAM_NAME == __FILE__
data/bin/bench_regression DELETED
@@ -1,316 +0,0 @@
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