appmap 0.35.1 → 0.38.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +1 -1
  3. data/.gitignore +2 -1
  4. data/.rubocop.yml +10 -0
  5. data/CHANGELOG.md +22 -0
  6. data/README.md +14 -8
  7. data/Rakefile +3 -2
  8. data/appmap.gemspec +2 -1
  9. data/appmap.yml +1 -7
  10. data/lib/appmap.rb +2 -2
  11. data/lib/appmap/class_map.rb +20 -6
  12. data/lib/appmap/config.rb +66 -22
  13. data/lib/appmap/event.rb +21 -6
  14. data/lib/appmap/hook/method.rb +18 -12
  15. data/lib/appmap/rails/request_handler.rb +8 -1
  16. data/lib/appmap/railtie.rb +1 -1
  17. data/lib/appmap/rspec.rb +1 -1
  18. data/lib/appmap/trace.rb +18 -7
  19. data/lib/appmap/version.rb +2 -2
  20. data/spec/abstract_controller4_base_spec.rb +27 -28
  21. data/spec/abstract_controller_base_spec.rb +73 -38
  22. data/spec/class_map_spec.rb +36 -0
  23. data/spec/fixtures/hook/exception_method.rb +44 -0
  24. data/spec/fixtures/hook/instance_method.rb +4 -0
  25. data/spec/fixtures/{rails_users_app → rails5_users_app}/.dockerignore +0 -0
  26. data/spec/fixtures/{rails_users_app → rails5_users_app}/.gitignore +0 -0
  27. data/spec/fixtures/{rails_users_app → rails5_users_app}/.rspec +0 -0
  28. data/{.ruby-version → spec/fixtures/rails5_users_app/.ruby-version} +0 -0
  29. data/spec/fixtures/{rails_users_app → rails5_users_app}/Dockerfile +0 -0
  30. data/spec/fixtures/{rails_users_app → rails5_users_app}/Dockerfile.pg +0 -0
  31. data/spec/fixtures/rails5_users_app/Gemfile +51 -0
  32. data/spec/fixtures/{rails_users_app → rails5_users_app}/Rakefile +0 -0
  33. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/controllers/api/users_controller.rb +0 -0
  34. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/controllers/application_controller.rb +0 -0
  35. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/controllers/concerns/.keep +0 -0
  36. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/controllers/health_controller.rb +0 -0
  37. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/controllers/users_controller.rb +0 -0
  38. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/models/activerecord/user.rb +0 -0
  39. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/models/concerns/.keep +0 -0
  40. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/models/sequel/user.rb +0 -0
  41. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/views/layouts/application.html.haml +0 -0
  42. data/spec/fixtures/{rails_users_app → rails5_users_app}/app/views/users/index.html.haml +0 -0
  43. data/spec/fixtures/rails5_users_app/appmap.yml +4 -0
  44. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/appmap +0 -0
  45. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/byebug +0 -0
  46. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/gli +0 -0
  47. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/htmldiff +0 -0
  48. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/ldiff +0 -0
  49. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/nokogiri +0 -0
  50. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/rackup +0 -0
  51. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/rails +0 -0
  52. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/rake +0 -0
  53. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/rspec +0 -0
  54. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/ruby-parse +0 -0
  55. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/ruby-rewrite +0 -0
  56. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/sequel +0 -0
  57. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/setup +0 -0
  58. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/sprockets +0 -0
  59. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/thor +0 -0
  60. data/spec/fixtures/{rails_users_app → rails5_users_app}/bin/update +0 -0
  61. data/spec/fixtures/{rails_users_app → rails5_users_app}/config.ru +0 -0
  62. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/application.rb +0 -0
  63. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/boot.rb +0 -0
  64. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/credentials.yml.enc +0 -0
  65. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/database.yml +0 -0
  66. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/environment.rb +0 -0
  67. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/environments/development.rb +0 -0
  68. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/environments/production.rb +0 -0
  69. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/environments/test.rb +0 -0
  70. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/application_controller_renderer.rb +0 -0
  71. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/backtrace_silencers.rb +0 -0
  72. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/cors.rb +0 -0
  73. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/filter_parameter_logging.rb +0 -0
  74. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/inflections.rb +0 -0
  75. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/mime_types.rb +0 -0
  76. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/record_button.rb +0 -0
  77. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/initializers/wrap_parameters.rb +0 -0
  78. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/locales/en.yml +0 -0
  79. data/spec/fixtures/{rails_users_app → rails5_users_app}/config/routes.rb +0 -0
  80. data/spec/fixtures/{rails_users_app → rails5_users_app}/create_app +0 -0
  81. data/spec/fixtures/{rails_users_app → rails5_users_app}/db/migrate/20190728211408_create_users.rb +0 -0
  82. data/spec/fixtures/{rails_users_app → rails5_users_app}/db/schema.rb +0 -0
  83. data/spec/fixtures/{rails_users_app → rails5_users_app}/docker-compose.yml +0 -0
  84. data/spec/fixtures/{rails_users_app → rails5_users_app}/features/api_users.feature +0 -0
  85. data/spec/fixtures/{rails_users_app → rails5_users_app}/features/support/env.rb +0 -0
  86. data/spec/fixtures/{rails_users_app → rails5_users_app}/features/support/hooks.rb +0 -0
  87. data/spec/fixtures/{rails_users_app → rails5_users_app}/features/support/steps.rb +0 -0
  88. data/spec/fixtures/{rails_users_app → rails5_users_app}/lib/tasks/.keep +0 -0
  89. data/spec/fixtures/{rails_users_app → rails5_users_app}/log/.keep +0 -0
  90. data/spec/fixtures/{rails_users_app → rails5_users_app}/public/robots.txt +0 -0
  91. data/spec/fixtures/{rails_users_app → rails5_users_app}/spec/controllers/users_controller_api_spec.rb +1 -1
  92. data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_spec.rb +16 -0
  93. data/spec/fixtures/{rails_users_app → rails5_users_app}/spec/models/user_spec.rb +0 -0
  94. data/spec/fixtures/{rails_users_app → rails5_users_app}/spec/rails_helper.rb +0 -0
  95. data/spec/fixtures/{rails_users_app → rails5_users_app}/spec/spec_helper.rb +0 -0
  96. data/spec/fixtures/{rails_users_app → rails5_users_app}/users_app/.gitignore +0 -0
  97. data/spec/fixtures/rails6_users_app/.dockerignore +1 -0
  98. data/spec/fixtures/rails6_users_app/.gitignore +39 -0
  99. data/spec/fixtures/rails6_users_app/.rspec +1 -0
  100. data/spec/fixtures/{rails_users_app → rails6_users_app}/.ruby-version +0 -0
  101. data/spec/fixtures/rails6_users_app/Dockerfile +29 -0
  102. data/spec/fixtures/rails6_users_app/Dockerfile.pg +3 -0
  103. data/spec/fixtures/{rails_users_app → rails6_users_app}/Gemfile +1 -1
  104. data/spec/fixtures/rails6_users_app/Rakefile +6 -0
  105. data/spec/fixtures/rails6_users_app/app/controllers/api/users_controller.rb +27 -0
  106. data/spec/fixtures/rails6_users_app/app/controllers/application_controller.rb +2 -0
  107. data/spec/fixtures/rails6_users_app/app/controllers/concerns/.keep +0 -0
  108. data/spec/fixtures/rails6_users_app/app/controllers/health_controller.rb +5 -0
  109. data/spec/fixtures/rails6_users_app/app/controllers/users_controller.rb +5 -0
  110. data/spec/fixtures/rails6_users_app/app/models/activerecord/user.rb +18 -0
  111. data/spec/fixtures/rails6_users_app/app/models/concerns/.keep +0 -0
  112. data/spec/fixtures/rails6_users_app/app/models/sequel/user.rb +25 -0
  113. data/spec/fixtures/rails6_users_app/app/views/layouts/application.html.haml +7 -0
  114. data/spec/fixtures/rails6_users_app/app/views/users/index.html.haml +7 -0
  115. data/spec/fixtures/rails6_users_app/appmap.yml +5 -0
  116. data/spec/fixtures/rails6_users_app/bin/appmap +29 -0
  117. data/spec/fixtures/rails6_users_app/bin/byebug +29 -0
  118. data/spec/fixtures/rails6_users_app/bin/gli +29 -0
  119. data/spec/fixtures/rails6_users_app/bin/htmldiff +29 -0
  120. data/spec/fixtures/rails6_users_app/bin/ldiff +29 -0
  121. data/spec/fixtures/rails6_users_app/bin/nokogiri +29 -0
  122. data/spec/fixtures/rails6_users_app/bin/rackup +29 -0
  123. data/spec/fixtures/rails6_users_app/bin/rails +4 -0
  124. data/spec/fixtures/rails6_users_app/bin/rake +29 -0
  125. data/spec/fixtures/rails6_users_app/bin/rspec +29 -0
  126. data/spec/fixtures/rails6_users_app/bin/ruby-parse +29 -0
  127. data/spec/fixtures/rails6_users_app/bin/ruby-rewrite +29 -0
  128. data/spec/fixtures/rails6_users_app/bin/sequel +29 -0
  129. data/spec/fixtures/rails6_users_app/bin/setup +25 -0
  130. data/spec/fixtures/rails6_users_app/bin/sprockets +29 -0
  131. data/spec/fixtures/rails6_users_app/bin/thor +29 -0
  132. data/spec/fixtures/rails6_users_app/bin/update +25 -0
  133. data/spec/fixtures/rails6_users_app/config.ru +5 -0
  134. data/spec/fixtures/rails6_users_app/config/application.rb +51 -0
  135. data/spec/fixtures/rails6_users_app/config/boot.rb +3 -0
  136. data/spec/fixtures/rails6_users_app/config/credentials.yml.enc +1 -0
  137. data/spec/fixtures/rails6_users_app/config/database.yml +18 -0
  138. data/spec/fixtures/rails6_users_app/config/environment.rb +5 -0
  139. data/spec/fixtures/rails6_users_app/config/environments/development.rb +40 -0
  140. data/spec/fixtures/rails6_users_app/config/environments/production.rb +68 -0
  141. data/spec/fixtures/rails6_users_app/config/environments/test.rb +36 -0
  142. data/spec/fixtures/rails6_users_app/config/initializers/application_controller_renderer.rb +8 -0
  143. data/spec/fixtures/rails6_users_app/config/initializers/backtrace_silencers.rb +7 -0
  144. data/spec/fixtures/rails6_users_app/config/initializers/cors.rb +16 -0
  145. data/spec/fixtures/rails6_users_app/config/initializers/filter_parameter_logging.rb +4 -0
  146. data/spec/fixtures/rails6_users_app/config/initializers/inflections.rb +16 -0
  147. data/spec/fixtures/rails6_users_app/config/initializers/mime_types.rb +4 -0
  148. data/spec/fixtures/rails6_users_app/config/initializers/record_button.rb +3 -0
  149. data/spec/fixtures/rails6_users_app/config/initializers/wrap_parameters.rb +9 -0
  150. data/spec/fixtures/rails6_users_app/config/locales/en.yml +33 -0
  151. data/spec/fixtures/rails6_users_app/config/routes.rb +11 -0
  152. data/spec/fixtures/rails6_users_app/create_app +27 -0
  153. data/spec/fixtures/rails6_users_app/db/migrate/20190728211408_create_users.rb +9 -0
  154. data/spec/fixtures/rails6_users_app/db/schema.rb +23 -0
  155. data/spec/fixtures/rails6_users_app/docker-compose.yml +28 -0
  156. data/spec/fixtures/rails6_users_app/features/api_users.feature +13 -0
  157. data/spec/fixtures/rails6_users_app/features/support/env.rb +4 -0
  158. data/spec/fixtures/rails6_users_app/features/support/hooks.rb +11 -0
  159. data/spec/fixtures/rails6_users_app/features/support/steps.rb +18 -0
  160. data/spec/fixtures/rails6_users_app/lib/tasks/.keep +0 -0
  161. data/spec/fixtures/rails6_users_app/log/.keep +0 -0
  162. data/spec/fixtures/rails6_users_app/public/robots.txt +1 -0
  163. data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_api_spec.rb +29 -0
  164. data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_spec.rb +16 -0
  165. data/spec/fixtures/rails6_users_app/spec/models/user_spec.rb +39 -0
  166. data/spec/fixtures/rails6_users_app/spec/rails_helper.rb +66 -0
  167. data/spec/fixtures/rails6_users_app/spec/spec_helper.rb +96 -0
  168. data/spec/fixtures/rails6_users_app/users_app/.gitignore +20 -0
  169. data/spec/hook_spec.rb +225 -18
  170. data/spec/rails_spec_helper.rb +5 -5
  171. data/spec/railtie_spec.rb +31 -32
  172. data/spec/record_sql_rails4_pg_spec.rb +47 -48
  173. data/spec/record_sql_rails_pg_spec.rb +62 -63
  174. data/spec/remote_recording_spec.rb +90 -89
  175. data/spec/rspec_feature_metadata_spec.rb +17 -18
  176. data/test/expectations/openssl_test_key_sign1.json +55 -0
  177. data/test/expectations/openssl_test_key_sign2.json +58 -0
  178. data/test/fixtures/gem_test/Gemfile +6 -0
  179. data/test/fixtures/gem_test/appmap.yml +3 -0
  180. data/test/fixtures/gem_test/test/to_param_test.rb +14 -0
  181. data/test/gem_test.rb +34 -0
  182. data/test/minitest_test.rb +2 -2
  183. data/test/openssl_test.rb +10 -117
  184. metadata +173 -80
  185. data/spec/fixtures/rails_users_app/appmap.yml +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: baf04e5395f8456142064fd8413363f6e29aa1bf2b68150e79b904d3879b8b7f
4
- data.tar.gz: ca27e18b4778b9341801ac81e25e9025ab26a047824b58ab4bcf113ab91fd5b9
3
+ metadata.gz: 0255347aa61c6f39bfec0f43a78b3cc3060bd20e4f80f1e39e0ff3714a52dff3
4
+ data.tar.gz: 822bc2fe118426d6d9c9437c85ead8e603a446cabd6bd49d0053c2b1cfaf3789
5
5
  SHA512:
6
- metadata.gz: f7a97d2d7a4e8bd5ae7db133e6287775dcff0373af82f187bc7d82411f868731e30fdb1a1267b173578a38d44017b20127cb20dcd7ddf3924d813e9ba6b32eb5
7
- data.tar.gz: 784ea7d032b9186d50352c0222b168887249b0a9bde5d850f4b2b98e12555ed728f1dc95c1604e2e45d7d6a15c6765eda467ddbd55530af859c82842a1aca4ca
6
+ metadata.gz: 031534a5eb015fa99d6ad161665b131677cadbe41ed1bce20357cb1ded7ba19e5f0bcbe37cfef0c8ad35cc2904fe83e4cc9d2b12d04260b970d24cc9aea64ba3
7
+ data.tar.gz: e7996262f4da21936567c1238df624220987ed04bf5aebd9a525da4d3f181ca752c1060056a5bb41b52c9cdb29e958cf7335973ac7076113278c7e8583755477
@@ -1,5 +1,5 @@
1
1
  vendor
2
2
  node_modules
3
- spec/fixtures/rails_users_app
3
+ spec/fixtures/rails*_users_app
4
4
  spec/fixtures/rack_users_app
5
5
 
data/.gitignore CHANGED
@@ -14,4 +14,5 @@ Gemfile.lock
14
14
  appmap.json
15
15
  .vscode
16
16
  .byebug_history
17
- /lib/appmap/appmap.bundle
17
+ /lib/appmap/appmap.bundle
18
+ *.so
@@ -1,3 +1,9 @@
1
+ AllCops:
2
+ NewCops: enable
3
+
4
+ Layout/CaseIndentation:
5
+ EnforcedStyle: end
6
+
1
7
  Layout/SpaceInsideArrayLiteralBrackets:
2
8
  Enabled: false
3
9
 
@@ -8,6 +14,10 @@ Layout/HeredocIndentation:
8
14
  Layout/LineLength:
9
15
  Max: 120
10
16
 
17
+ Metrics/BlockLength:
18
+ ExcludedMethods:
19
+ - it
20
+
11
21
  Style/MultilineBlockChain:
12
22
  Enabled: false
13
23
 
@@ -1,3 +1,25 @@
1
+ # v0.38.1
2
+
3
+ * Package configuration can be `shallow`, in case which only the initial entry into the package is recorded.
4
+
5
+ # v0.37.2
6
+ * Fix ParameterFilter deprecation warning.
7
+
8
+ # v0.37.1
9
+ * Fix parameter mapping with keyword and rest arguments.
10
+
11
+ # v0.37.0
12
+ * Capture method source and comment.
13
+
14
+ # v0.36.0
15
+ * *appmap.yml* package definition may specify `gem`.
16
+ * Skip loading the railtie if `APPMAP_INITIALIZE` environment variable
17
+ is set to `false`.
18
+
19
+ # v0.35.2
20
+ * Make sure `MethodEvent#display_string` works when the value's `#to_s` and/or `#inspect`
21
+ methods have problems.
22
+
1
23
  # v0.35.1
2
24
  * Take out hooking of `IO` and `Logger` methods.
3
25
  * Enable logging if either `APPMAP_DEBUG` or `DEBUG` is `true`.
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  - [About](#about)
2
3
  - [Installation](#installation)
3
4
  - [Configuration](#configuration)
@@ -13,7 +14,7 @@
13
14
  - [Using fixture apps](#using-fixture-apps)
14
15
  - [`test/fixtures`](#testfixtures)
15
16
  - [`spec/fixtures`](#specfixtures)
16
- - [Build status](#build-status)
17
+
17
18
 
18
19
  # About
19
20
 
@@ -27,8 +28,9 @@ granular than a full debug trace. It's designed to be optimal for understanding
27
28
  There are several ways to record AppMaps of your Ruby program using the `appmap` gem:
28
29
 
29
30
  * Run your RSpec tests with the environment variable `APPMAP=true`. An AppMap will be generated for each spec.
30
- * Run your application server with AppMap remote recording enabled, and use the AppMap.
31
- browser extension to start, stop, and upload recordings.
31
+ * Run your application server with AppMap remote recording enabled, and use the [AppLand
32
+ browser extension](https://github.com/applandinc/appland-browser-extension) to start,
33
+ stop, and upload recordings.
32
34
  * Run the command `appmap record <program>` to record the entire execution of a program.
33
35
 
34
36
  Once you have recorded some AppMaps (for example, by running RSpec tests), you use the `appland upload` command
@@ -76,6 +78,7 @@ name: MyProject
76
78
  packages:
77
79
  - path: app/controllers
78
80
  - path: app/models
81
+ - gem: activerecord
79
82
  ```
80
83
 
81
84
  * **name** Provides the project name (required)
@@ -87,8 +90,12 @@ Each entry in the `packages` list is a YAML object which has the following keys:
87
90
 
88
91
  * **path** The path to the source code directory. The path may be relative to the current working directory, or it may
89
92
  be an absolute path.
93
+ * **gem** As an alternative to specifying the path, specify the name of a dependency gem. When using `gem`, don't specify `path`.
90
94
  * **exclude** A list of files and directories which will be ignored. By default, all modules, classes and public
91
95
  functions are inspected.
96
+ * **shallow** When set to `true`, only the first function call entry into a package will be recorded. Subsequent function calls within
97
+ the same package are not recorded unless code execution leaves the package and re-enters it. Default: `true` when using `gem`,
98
+ `false` when using `path`.
92
99
 
93
100
  # Running
94
101
 
@@ -248,11 +255,11 @@ end
248
255
  $ bundle exec rails server
249
256
  ```
250
257
 
251
- 4. Open the AppApp browser extension and push `Start`.
258
+ 4. Open the AppLand browser extension and push `Start`.
252
259
 
253
260
  5. Use your app. For example, perform a login flow, or run through a manual UI test.
254
261
 
255
- 6. Open the AppApp browser extension and push `Stop`. The recording will be transferred to the AppLand website and opened in your browser.
262
+ 6. Open the AppLand browser extension and push `Stop`. The recording will be transferred to the AppLand website and opened in your browser.
256
263
 
257
264
  ## Ruby on Rails
258
265
 
@@ -265,6 +272,7 @@ Note that using this method is kind of a blunt instrument. Recording RSpecs and
265
272
  For instructions on uploading, see the documentation of the [AppLand CLI](https://github.com/applandinc/appland-cli).
266
273
 
267
274
  # Development
275
+ [![Build Status](https://travis-ci.org/applandinc/appmap-ruby.svg?branch=master)](https://travis-ci.org/applandinc/appmap-ruby)
268
276
 
269
277
  ## Running tests
270
278
 
@@ -289,7 +297,7 @@ $ bundle exec rake compile
289
297
  ### `test/fixtures`
290
298
 
291
299
  The fixture apps in `test/fixtures` are plain Ruby projects that exercise the basic functionality of the
292
- `appmap` gem. To develop in a fixture, simple enter the fixture directory and `bundle`.
300
+ `appmap` gem. To develop in a fixture, simply enter the fixture directory and `bundle`.
293
301
 
294
302
  ### `spec/fixtures`
295
303
 
@@ -339,5 +347,3 @@ Finished in 0.07357 seconds (files took 2.1 seconds to load)
339
347
  4 examples, 0 failures
340
348
  ```
341
349
 
342
- # Build status
343
- [![Build Status](https://travis-ci.org/applandinc/appmap-ruby.svg?branch=master)](https://travis-ci.org/applandinc/appmap-ruby)
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ $: << File.join(__dir__, 'lib')
1
2
  require 'appmap/version'
2
3
  GEM_VERSION = AppMap::VERSION
3
4
 
@@ -18,7 +19,7 @@ namespace 'gem' do
18
19
  end
19
20
 
20
21
  RUBY_VERSIONS=%w[2.5 2.6]
21
- FIXTURE_APPS=%w[rack_users_app rails_users_app rails4_users_app]
22
+ FIXTURE_APPS=%w[rack_users_app rails6_users_app rails5_users_app rails4_users_app]
22
23
 
23
24
  def run_cmd(*cmd)
24
25
  $stderr.puts "Running: #{cmd}"
@@ -113,7 +114,7 @@ namespace :spec do
113
114
  desc ruby_version
114
115
  task ruby_version, [:specs] => ["compile", "build:fixtures:#{ruby_version}:all"] do |_, task_args|
115
116
  run_specs(ruby_version, task_args)
116
- end.tap do|t|
117
+ end.tap do |t|
117
118
  desc "Run all specs"
118
119
  task :all, [:specs] => t
119
120
  end
@@ -27,10 +27,11 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'activesupport'
28
28
  spec.add_dependency 'faraday'
29
29
  spec.add_dependency 'gli'
30
+ spec.add_dependency 'method_source'
30
31
  spec.add_dependency 'parser'
31
32
  spec.add_dependency 'rack'
32
33
 
33
- spec.add_development_dependency 'bundler', '~> 1.16'
34
+ spec.add_development_dependency 'bundler', '>= 1.16'
34
35
  spec.add_development_dependency 'minitest', '~> 5.0'
35
36
  spec.add_development_dependency 'pry-byebug'
36
37
  spec.add_development_dependency 'rake', '>= 12.3.3'
data/appmap.yml CHANGED
@@ -1,8 +1,2 @@
1
1
  name: AppMap Rubygem
2
- packages:
3
- - path: lib/appmap
4
- exclude:
5
- - server
6
- - trace
7
-
8
- - path: examples
2
+ packages: []
@@ -83,8 +83,8 @@ module AppMap
83
83
  end
84
84
 
85
85
  # Builds a class map from a config and a list of Ruby methods.
86
- def class_map(methods)
87
- ClassMap.build_from_methods(methods)
86
+ def class_map(methods, options = {})
87
+ ClassMap.build_from_methods(methods, options)
88
88
  end
89
89
 
90
90
  # Returns default metadata detected from the Ruby system and from the
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'method_source'
4
+
3
5
  module AppMap
4
6
  class ClassMap
5
7
  module HasChildren
@@ -48,7 +50,7 @@ module AppMap
48
50
  end
49
51
  end
50
52
  Function = Struct.new(:name) do
51
- attr_accessor :static, :location, :labels
53
+ attr_accessor :static, :location, :labels, :comment, :source
52
54
 
53
55
  def type
54
56
  'function'
@@ -60,30 +62,32 @@ module AppMap
60
62
  type: type,
61
63
  location: location,
62
64
  static: static,
63
- labels: labels
65
+ labels: labels,
66
+ comment: comment,
67
+ source: source
64
68
  }.delete_if { |_, v| v.nil? || v == [] }
65
69
  end
66
70
  end
67
71
  end
68
72
 
69
73
  class << self
70
- def build_from_methods(methods)
74
+ def build_from_methods(methods, options = {})
71
75
  root = Types::Root.new
72
76
  methods.each do |method|
73
- add_function root, method
77
+ add_function root, method, options
74
78
  end
75
79
  root.children.map(&:to_h)
76
80
  end
77
81
 
78
82
  protected
79
83
 
80
- def add_function(root, method)
84
+ def add_function(root, method, include_source: true)
81
85
  package = method.package
82
86
  static = method.static
83
87
 
84
88
  object_infos = [
85
89
  {
86
- name: package.path,
90
+ name: package.name,
87
91
  type: 'package'
88
92
  }
89
93
  ]
@@ -109,6 +113,16 @@ module AppMap
109
113
  [ method.defined_class, static ? '.' : '#', method.name ].join
110
114
  end
111
115
 
116
+ if include_source
117
+ begin
118
+ function_info[:source] = method.source
119
+ comment = method.comment || ''
120
+ function_info[:comment] = comment unless comment.empty?
121
+ rescue MethodSource::SourceNotFoundError
122
+ # pass
123
+ end
124
+ end
125
+
112
126
  function_info[:labels] = package.labels if package.labels
113
127
  object_infos << function_info
114
128
 
@@ -2,17 +2,49 @@
2
2
 
3
3
  module AppMap
4
4
  class Config
5
- Package = Struct.new(:path, :package_name, :exclude, :labels) do
6
- def initialize(path, package_name: nil, exclude: [], labels: [])
7
- super path, package_name, exclude, labels
5
+ Package = Struct.new(:path, :gem, :package_name, :exclude, :labels, :shallow) do
6
+ # Indicates that only the entry points to a package will be recorded.
7
+ # Once the code has entered a package, subsequent calls within the package will not be
8
+ # recorded unless the code leaves the package and re-enters it.
9
+ def shallow?
10
+ shallow
11
+ end
12
+
13
+ class << self
14
+ def build_from_path(path, shallow: false, package_name: nil, exclude: [], labels: [])
15
+ Package.new(path, nil, package_name, exclude, labels, shallow)
16
+ end
17
+
18
+ def build_from_gem(gem, shallow: true, package_name: nil, exclude: [], labels: [])
19
+ gem_paths(gem).map do |gem_path|
20
+ Package.new(gem_path, gem, package_name, exclude, labels, shallow)
21
+ end
22
+ end
23
+
24
+ private_class_method :new
25
+
26
+ protected
27
+
28
+ def gem_paths(gem)
29
+ gemspec = Gem.loaded_specs[gem] or raise "Gem #{gem.inspect} not found"
30
+ gemspec.source_paths.map do |path|
31
+ File.join(gemspec.gem_dir, path)
32
+ end
33
+ end
34
+ end
35
+
36
+ def name
37
+ gem || path
8
38
  end
9
39
 
10
40
  def to_h
11
41
  {
12
42
  path: path,
13
43
  package_name: package_name,
44
+ gem: gem,
14
45
  exclude: exclude.blank? ? nil : exclude,
15
- labels: labels.blank? ? nil : labels
46
+ labels: labels.blank? ? nil : labels,
47
+ shallow: shallow
16
48
  }.compact
17
49
  end
18
50
  end
@@ -20,29 +52,30 @@ module AppMap
20
52
  Hook = Struct.new(:method_names, :package) do
21
53
  end
22
54
 
23
- OPENSSL_PACKAGE = Package.new('openssl', package_name: 'openssl', labels: %w[security crypto])
55
+ OPENSSL_PACKAGES = Package.build_from_path('openssl', package_name: 'openssl', labels: %w[security crypto])
24
56
 
25
57
  # Methods that should always be hooked, with their containing
26
58
  # package and labels that should be applied to them.
27
59
  HOOKED_METHODS = {
28
- 'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.new('active_support', package_name: 'active_support', labels: %w[security crypto]))
60
+ 'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.build_from_path('active_support', package_name: 'active_support', labels: %w[security crypto])),
61
+ 'ActionView::Renderer' => Hook.new(:render, Package.build_from_path('action_view', package_name: 'action_view', labels: %w[view]))
29
62
  }.freeze
30
63
 
31
64
  BUILTIN_METHODS = {
32
- 'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGE),
33
- 'Digest::Instance' => Hook.new(:digest, OPENSSL_PACKAGE),
34
- 'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGE),
35
- 'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGE),
36
- 'OpenSSL::Cipher' => Hook.new(%i[encrypt decrypt final], OPENSSL_PACKAGE),
37
- 'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGE),
38
- 'Net::HTTP' => Hook.new(:request, Package.new('net/http', package_name: 'net/http', labels: %w[http io])),
39
- 'Net::SMTP' => Hook.new(:send, Package.new('net/smtp', package_name: 'net/smtp', labels: %w[smtp email io])),
40
- 'Net::POP3' => Hook.new(:mails, Package.new('net/pop3', package_name: 'net/pop', labels: %w[pop pop3 email io])),
41
- 'Net::IMAP' => Hook.new(:send_command, Package.new('net/imap', package_name: 'net/imap', labels: %w[imap email io])),
42
- 'Marshal' => Hook.new(%i[dump load], Package.new('marshal', labels: %w[serialization marshal])),
43
- 'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.new('yaml', package_name: 'psych', labels: %w[serialization yaml])),
44
- 'JSON::Ext::Parser' => Hook.new(:parse, Package.new('json', package_name: 'json', labels: %w[serialization json])),
45
- 'JSON::Ext::Generator::State' => Hook.new(:generate, Package.new('json', package_name: 'json', labels: %w[serialization json]))
65
+ 'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGES),
66
+ 'Digest::Instance' => Hook.new(:digest, OPENSSL_PACKAGES),
67
+ 'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGES),
68
+ 'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES),
69
+ 'OpenSSL::Cipher' => Hook.new(%i[encrypt decrypt final], OPENSSL_PACKAGES),
70
+ 'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGES),
71
+ 'Net::HTTP' => Hook.new(:request, Package.build_from_path('net/http', package_name: 'net/http', labels: %w[http io])),
72
+ 'Net::SMTP' => Hook.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[smtp email io])),
73
+ 'Net::POP3' => Hook.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[pop pop3 email io])),
74
+ 'Net::IMAP' => Hook.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[imap email io])),
75
+ 'Marshal' => Hook.new(%i[dump load], Package.build_from_path('marshal', labels: %w[serialization marshal])),
76
+ 'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[serialization yaml])),
77
+ 'JSON::Ext::Parser' => Hook.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[serialization json])),
78
+ 'JSON::Ext::Generator::State' => Hook.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[serialization json])),
46
79
  }.freeze
47
80
 
48
81
  attr_reader :name, :packages
@@ -62,8 +95,19 @@ module AppMap
62
95
  # Loads configuration from a Hash.
63
96
  def load(config_data)
64
97
  packages = (config_data['packages'] || []).map do |package|
65
- Package.new(package['path'], exclude: package['exclude'] || [])
66
- end
98
+ gem = package['gem']
99
+ path = package['path']
100
+ raise 'AppMap package configuration should specify gem or path, not both' if gem && path
101
+
102
+ if gem
103
+ shallow = package['shallow']
104
+ # shallow is true by default for gems
105
+ shallow = true if shallow.nil?
106
+ Package.build_from_gem(gem, exclude: package['exclude'] || [], shallow: shallow)
107
+ else
108
+ [ Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow']) ]
109
+ end
110
+ end.flatten
67
111
  Config.new config_data['name'], packages
68
112
  end
69
113
  end
@@ -31,11 +31,6 @@ module AppMap
31
31
  def display_string(value)
32
32
  return nil unless value
33
33
 
34
- last_resort_string = lambda do
35
- warn "AppMap encountered an error inspecting a #{value.class.name}: #{$!.message}"
36
- '*Error inspecting variable*'
37
- end
38
-
39
34
  value_string = custom_display_string(value) || default_display_string(value)
40
35
 
41
36
  (value_string||'')[0...LIMIT].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
@@ -57,6 +52,11 @@ module AppMap
57
52
  end
58
53
 
59
54
  def default_display_string(value)
55
+ last_resort_string = lambda do
56
+ warn "AppMap encountered an error inspecting a #{value.class.name}: #{$!.message}"
57
+ '*Error inspecting variable*'
58
+ end
59
+
60
60
  begin
61
61
  value.to_s
62
62
  rescue NoMethodError
@@ -89,10 +89,25 @@ module AppMap
89
89
  else
90
90
  mc.path = [ defined_class, static ? '.' : '#', method.name ].join
91
91
  end
92
+
93
+ # Check if the method has key parameters. If there are any they'll always be last.
94
+ # If yes, then extract it from arguments.
95
+ has_key = [[:dummy], *method.parameters].last.first.to_s.start_with?('key') && arguments[-1].is_a?(Hash)
96
+ kwargs = has_key && arguments[-1].dup || {}
97
+
92
98
  mc.parameters = method.parameters.map.with_index do |method_param, idx|
93
99
  param_type, param_name = method_param
94
100
  param_name ||= 'arg'
95
- value = arguments[idx]
101
+ value = case param_type
102
+ when :keyrest
103
+ kwargs
104
+ when /^key/
105
+ kwargs.delete param_name
106
+ when :rest
107
+ arguments[idx..(has_key ? -2 : -1)]
108
+ else
109
+ arguments[idx]
110
+ end
96
111
  {
97
112
  name: param_name,
98
113
  class: value.class.name,