activerecord 2.3.18 → 3.2.22

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (454) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1014 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +222 -0
  5. data/examples/performance.rb +100 -126
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +93 -99
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +247 -0
  10. data/lib/active_record/associations/association_scope.rb +134 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +54 -61
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +17 -59
  13. data/lib/active_record/associations/builder/association.rb +55 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +88 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  17. data/lib/active_record/associations/builder/has_many.rb +71 -0
  18. data/lib/active_record/associations/builder/has_one.rb +62 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +580 -0
  21. data/lib/active_record/associations/collection_proxy.rb +133 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +39 -119
  23. data/lib/active_record/associations/has_many_association.rb +60 -79
  24. data/lib/active_record/associations/has_many_through_association.rb +127 -206
  25. data/lib/active_record/associations/has_one_association.rb +55 -114
  26. data/lib/active_record/associations/has_one_through_association.rb +25 -26
  27. data/lib/active_record/associations/join_dependency/join_association.rb +159 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +214 -0
  31. data/lib/active_record/associations/join_helper.rb +55 -0
  32. data/lib/active_record/associations/preloader/association.rb +125 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  42. data/lib/active_record/associations/preloader.rb +181 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +693 -1337
  46. data/lib/active_record/attribute_assignment.rb +221 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  48. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  49. data/lib/active_record/attribute_methods/dirty.rb +111 -0
  50. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  51. data/lib/active_record/attribute_methods/query.rb +39 -0
  52. data/lib/active_record/attribute_methods/read.rb +136 -0
  53. data/lib/active_record/attribute_methods/serialization.rb +120 -0
  54. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
  55. data/lib/active_record/attribute_methods/write.rb +70 -0
  56. data/lib/active_record/attribute_methods.rb +211 -339
  57. data/lib/active_record/autosave_association.rb +179 -149
  58. data/lib/active_record/base.rb +401 -2907
  59. data/lib/active_record/callbacks.rb +91 -176
  60. data/lib/active_record/coders/yaml_column.rb +41 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +236 -119
  62. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +110 -58
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -74
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -35
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +71 -21
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +81 -311
  68. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +194 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +130 -83
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
  71. data/lib/active_record/connection_adapters/column.rb +296 -0
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +280 -0
  73. data/lib/active_record/connection_adapters/mysql_adapter.rb +272 -493
  74. data/lib/active_record/connection_adapters/postgresql_adapter.rb +650 -405
  75. data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
  76. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +30 -9
  77. data/lib/active_record/connection_adapters/sqlite_adapter.rb +276 -147
  78. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  79. data/lib/active_record/counter_cache.rb +123 -0
  80. data/lib/active_record/dynamic_finder_match.rb +41 -14
  81. data/lib/active_record/dynamic_matchers.rb +84 -0
  82. data/lib/active_record/dynamic_scope_match.rb +13 -15
  83. data/lib/active_record/errors.rb +195 -0
  84. data/lib/active_record/explain.rb +86 -0
  85. data/lib/active_record/explain_subscriber.rb +25 -0
  86. data/lib/active_record/fixtures/file.rb +65 -0
  87. data/lib/active_record/fixtures.rb +695 -770
  88. data/lib/active_record/identity_map.rb +162 -0
  89. data/lib/active_record/inheritance.rb +174 -0
  90. data/lib/active_record/integration.rb +60 -0
  91. data/lib/active_record/locale/en.yml +9 -27
  92. data/lib/active_record/locking/optimistic.rb +76 -73
  93. data/lib/active_record/locking/pessimistic.rb +32 -10
  94. data/lib/active_record/log_subscriber.rb +72 -0
  95. data/lib/active_record/migration/command_recorder.rb +105 -0
  96. data/lib/active_record/migration.rb +415 -205
  97. data/lib/active_record/model_schema.rb +368 -0
  98. data/lib/active_record/nested_attributes.rb +153 -63
  99. data/lib/active_record/observer.rb +27 -103
  100. data/lib/active_record/persistence.rb +376 -0
  101. data/lib/active_record/query_cache.rb +49 -8
  102. data/lib/active_record/querying.rb +58 -0
  103. data/lib/active_record/railtie.rb +131 -0
  104. data/lib/active_record/railties/console_sandbox.rb +6 -0
  105. data/lib/active_record/railties/controller_runtime.rb +49 -0
  106. data/lib/active_record/railties/databases.rake +659 -0
  107. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  108. data/lib/active_record/readonly_attributes.rb +26 -0
  109. data/lib/active_record/reflection.rb +269 -120
  110. data/lib/active_record/relation/batches.rb +90 -0
  111. data/lib/active_record/relation/calculations.rb +372 -0
  112. data/lib/active_record/relation/delegation.rb +49 -0
  113. data/lib/active_record/relation/finder_methods.rb +402 -0
  114. data/lib/active_record/relation/predicate_builder.rb +63 -0
  115. data/lib/active_record/relation/query_methods.rb +417 -0
  116. data/lib/active_record/relation/spawn_methods.rb +180 -0
  117. data/lib/active_record/relation.rb +537 -0
  118. data/lib/active_record/result.rb +40 -0
  119. data/lib/active_record/sanitization.rb +194 -0
  120. data/lib/active_record/schema.rb +9 -6
  121. data/lib/active_record/schema_dumper.rb +55 -32
  122. data/lib/active_record/scoping/default.rb +142 -0
  123. data/lib/active_record/scoping/named.rb +200 -0
  124. data/lib/active_record/scoping.rb +152 -0
  125. data/lib/active_record/serialization.rb +8 -91
  126. data/lib/active_record/serializers/xml_serializer.rb +43 -197
  127. data/lib/active_record/session_store.rb +129 -103
  128. data/lib/active_record/store.rb +52 -0
  129. data/lib/active_record/test_case.rb +30 -23
  130. data/lib/active_record/timestamp.rb +95 -52
  131. data/lib/active_record/transactions.rb +212 -66
  132. data/lib/active_record/translation.rb +22 -0
  133. data/lib/active_record/validations/associated.rb +43 -0
  134. data/lib/active_record/validations/uniqueness.rb +180 -0
  135. data/lib/active_record/validations.rb +43 -1106
  136. data/lib/active_record/version.rb +5 -4
  137. data/lib/active_record.rb +121 -48
  138. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  139. data/lib/rails/generators/active_record/migration/templates/migration.rb +34 -0
  140. data/lib/rails/generators/active_record/migration.rb +15 -0
  141. data/lib/rails/generators/active_record/model/model_generator.rb +47 -0
  142. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  143. data/lib/rails/generators/active_record/model/templates/model.rb +12 -0
  144. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  145. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  146. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  147. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  148. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  149. data/lib/rails/generators/active_record.rb +25 -0
  150. metadata +187 -363
  151. data/CHANGELOG +0 -5904
  152. data/README +0 -351
  153. data/RUNNING_UNIT_TESTS +0 -36
  154. data/Rakefile +0 -268
  155. data/install.rb +0 -30
  156. data/lib/active_record/association_preload.rb +0 -406
  157. data/lib/active_record/associations/association_collection.rb +0 -533
  158. data/lib/active_record/associations/association_proxy.rb +0 -288
  159. data/lib/active_record/batches.rb +0 -85
  160. data/lib/active_record/calculations.rb +0 -321
  161. data/lib/active_record/dirty.rb +0 -183
  162. data/lib/active_record/named_scope.rb +0 -197
  163. data/lib/active_record/serializers/json_serializer.rb +0 -91
  164. data/lib/activerecord.rb +0 -2
  165. data/test/assets/example.log +0 -1
  166. data/test/assets/flowers.jpg +0 -0
  167. data/test/cases/aaa_create_tables_test.rb +0 -24
  168. data/test/cases/active_schema_test_mysql.rb +0 -122
  169. data/test/cases/active_schema_test_postgresql.rb +0 -24
  170. data/test/cases/adapter_test.rb +0 -144
  171. data/test/cases/aggregations_test.rb +0 -167
  172. data/test/cases/ar_schema_test.rb +0 -32
  173. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  174. data/test/cases/associations/callbacks_test.rb +0 -161
  175. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  176. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  177. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  178. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  179. data/test/cases/associations/eager_singularization_test.rb +0 -145
  180. data/test/cases/associations/eager_test.rb +0 -852
  181. data/test/cases/associations/extension_test.rb +0 -62
  182. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  183. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  184. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  185. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  186. data/test/cases/associations/has_one_associations_test.rb +0 -330
  187. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  188. data/test/cases/associations/inner_join_association_test.rb +0 -93
  189. data/test/cases/associations/inverse_associations_test.rb +0 -566
  190. data/test/cases/associations/join_model_test.rb +0 -712
  191. data/test/cases/associations_test.rb +0 -282
  192. data/test/cases/attribute_methods_test.rb +0 -305
  193. data/test/cases/autosave_association_test.rb +0 -1218
  194. data/test/cases/base_test.rb +0 -2166
  195. data/test/cases/batches_test.rb +0 -81
  196. data/test/cases/binary_test.rb +0 -30
  197. data/test/cases/calculations_test.rb +0 -360
  198. data/test/cases/callbacks_observers_test.rb +0 -38
  199. data/test/cases/callbacks_test.rb +0 -438
  200. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  201. data/test/cases/column_alias_test.rb +0 -17
  202. data/test/cases/column_definition_test.rb +0 -70
  203. data/test/cases/connection_pool_test.rb +0 -25
  204. data/test/cases/connection_test_firebird.rb +0 -8
  205. data/test/cases/connection_test_mysql.rb +0 -65
  206. data/test/cases/copy_table_test_sqlite.rb +0 -80
  207. data/test/cases/counter_cache_test.rb +0 -84
  208. data/test/cases/database_statements_test.rb +0 -12
  209. data/test/cases/datatype_test_postgresql.rb +0 -204
  210. data/test/cases/date_time_test.rb +0 -37
  211. data/test/cases/default_test_firebird.rb +0 -16
  212. data/test/cases/defaults_test.rb +0 -111
  213. data/test/cases/deprecated_finder_test.rb +0 -30
  214. data/test/cases/dirty_test.rb +0 -316
  215. data/test/cases/finder_respond_to_test.rb +0 -76
  216. data/test/cases/finder_test.rb +0 -1098
  217. data/test/cases/fixtures_test.rb +0 -661
  218. data/test/cases/helper.rb +0 -68
  219. data/test/cases/i18n_test.rb +0 -46
  220. data/test/cases/inheritance_test.rb +0 -262
  221. data/test/cases/invalid_date_test.rb +0 -24
  222. data/test/cases/json_serialization_test.rb +0 -219
  223. data/test/cases/lifecycle_test.rb +0 -193
  224. data/test/cases/locking_test.rb +0 -350
  225. data/test/cases/method_scoping_test.rb +0 -704
  226. data/test/cases/migration_test.rb +0 -1649
  227. data/test/cases/migration_test_firebird.rb +0 -124
  228. data/test/cases/mixin_test.rb +0 -96
  229. data/test/cases/modules_test.rb +0 -109
  230. data/test/cases/multiple_db_test.rb +0 -85
  231. data/test/cases/named_scope_test.rb +0 -372
  232. data/test/cases/nested_attributes_test.rb +0 -840
  233. data/test/cases/pk_test.rb +0 -119
  234. data/test/cases/pooled_connections_test.rb +0 -103
  235. data/test/cases/query_cache_test.rb +0 -129
  236. data/test/cases/readonly_test.rb +0 -107
  237. data/test/cases/reflection_test.rb +0 -234
  238. data/test/cases/reload_models_test.rb +0 -22
  239. data/test/cases/repair_helper.rb +0 -50
  240. data/test/cases/reserved_word_test_mysql.rb +0 -176
  241. data/test/cases/sanitize_test.rb +0 -25
  242. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  243. data/test/cases/schema_dumper_test.rb +0 -211
  244. data/test/cases/schema_test_postgresql.rb +0 -178
  245. data/test/cases/serialization_test.rb +0 -47
  246. data/test/cases/sp_test_mysql.rb +0 -16
  247. data/test/cases/synonym_test_oracle.rb +0 -17
  248. data/test/cases/timestamp_test.rb +0 -75
  249. data/test/cases/transactions_test.rb +0 -543
  250. data/test/cases/unconnected_test.rb +0 -32
  251. data/test/cases/validations_i18n_test.rb +0 -925
  252. data/test/cases/validations_test.rb +0 -1684
  253. data/test/cases/xml_serialization_test.rb +0 -240
  254. data/test/cases/yaml_serialization_test.rb +0 -11
  255. data/test/config.rb +0 -5
  256. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  257. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  258. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  259. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  260. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  261. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  262. data/test/connections/native_db2/connection.rb +0 -25
  263. data/test/connections/native_firebird/connection.rb +0 -26
  264. data/test/connections/native_frontbase/connection.rb +0 -27
  265. data/test/connections/native_mysql/connection.rb +0 -25
  266. data/test/connections/native_openbase/connection.rb +0 -21
  267. data/test/connections/native_oracle/connection.rb +0 -27
  268. data/test/connections/native_postgresql/connection.rb +0 -21
  269. data/test/connections/native_sqlite/connection.rb +0 -25
  270. data/test/connections/native_sqlite3/connection.rb +0 -25
  271. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  272. data/test/connections/native_sybase/connection.rb +0 -23
  273. data/test/fixtures/accounts.yml +0 -29
  274. data/test/fixtures/all/developers.yml +0 -0
  275. data/test/fixtures/all/people.csv +0 -0
  276. data/test/fixtures/all/tasks.yml +0 -0
  277. data/test/fixtures/author_addresses.yml +0 -5
  278. data/test/fixtures/author_favorites.yml +0 -4
  279. data/test/fixtures/authors.yml +0 -9
  280. data/test/fixtures/binaries.yml +0 -132
  281. data/test/fixtures/books.yml +0 -7
  282. data/test/fixtures/categories/special_categories.yml +0 -9
  283. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  284. data/test/fixtures/categories.yml +0 -14
  285. data/test/fixtures/categories_ordered.yml +0 -7
  286. data/test/fixtures/categories_posts.yml +0 -23
  287. data/test/fixtures/categorizations.yml +0 -17
  288. data/test/fixtures/clubs.yml +0 -6
  289. data/test/fixtures/comments.yml +0 -59
  290. data/test/fixtures/companies.yml +0 -56
  291. data/test/fixtures/computers.yml +0 -4
  292. data/test/fixtures/courses.yml +0 -7
  293. data/test/fixtures/customers.yml +0 -26
  294. data/test/fixtures/developers.yml +0 -21
  295. data/test/fixtures/developers_projects.yml +0 -17
  296. data/test/fixtures/edges.yml +0 -6
  297. data/test/fixtures/entrants.yml +0 -14
  298. data/test/fixtures/faces.yml +0 -11
  299. data/test/fixtures/fk_test_has_fk.yml +0 -3
  300. data/test/fixtures/fk_test_has_pk.yml +0 -2
  301. data/test/fixtures/funny_jokes.yml +0 -10
  302. data/test/fixtures/interests.yml +0 -33
  303. data/test/fixtures/items.yml +0 -4
  304. data/test/fixtures/jobs.yml +0 -7
  305. data/test/fixtures/legacy_things.yml +0 -3
  306. data/test/fixtures/mateys.yml +0 -4
  307. data/test/fixtures/member_types.yml +0 -6
  308. data/test/fixtures/members.yml +0 -6
  309. data/test/fixtures/memberships.yml +0 -20
  310. data/test/fixtures/men.yml +0 -5
  311. data/test/fixtures/minimalistics.yml +0 -2
  312. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  313. data/test/fixtures/mixins.yml +0 -29
  314. data/test/fixtures/movies.yml +0 -7
  315. data/test/fixtures/naked/csv/accounts.csv +0 -1
  316. data/test/fixtures/naked/yml/accounts.yml +0 -1
  317. data/test/fixtures/naked/yml/companies.yml +0 -1
  318. data/test/fixtures/naked/yml/courses.yml +0 -1
  319. data/test/fixtures/organizations.yml +0 -5
  320. data/test/fixtures/owners.yml +0 -7
  321. data/test/fixtures/parrots.yml +0 -27
  322. data/test/fixtures/parrots_pirates.yml +0 -7
  323. data/test/fixtures/people.yml +0 -15
  324. data/test/fixtures/pets.yml +0 -14
  325. data/test/fixtures/pirates.yml +0 -9
  326. data/test/fixtures/polymorphic_designs.yml +0 -19
  327. data/test/fixtures/polymorphic_prices.yml +0 -19
  328. data/test/fixtures/posts.yml +0 -52
  329. data/test/fixtures/price_estimates.yml +0 -7
  330. data/test/fixtures/projects.yml +0 -7
  331. data/test/fixtures/readers.yml +0 -9
  332. data/test/fixtures/references.yml +0 -17
  333. data/test/fixtures/reserved_words/distinct.yml +0 -5
  334. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  335. data/test/fixtures/reserved_words/group.yml +0 -14
  336. data/test/fixtures/reserved_words/select.yml +0 -8
  337. data/test/fixtures/reserved_words/values.yml +0 -7
  338. data/test/fixtures/ships.yml +0 -5
  339. data/test/fixtures/sponsors.yml +0 -9
  340. data/test/fixtures/subscribers.yml +0 -7
  341. data/test/fixtures/subscriptions.yml +0 -12
  342. data/test/fixtures/taggings.yml +0 -28
  343. data/test/fixtures/tags.yml +0 -7
  344. data/test/fixtures/tasks.yml +0 -7
  345. data/test/fixtures/tees.yml +0 -4
  346. data/test/fixtures/ties.yml +0 -4
  347. data/test/fixtures/topics.yml +0 -42
  348. data/test/fixtures/toys.yml +0 -4
  349. data/test/fixtures/treasures.yml +0 -10
  350. data/test/fixtures/vertices.yml +0 -4
  351. data/test/fixtures/warehouse-things.yml +0 -3
  352. data/test/fixtures/zines.yml +0 -5
  353. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  354. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  355. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  356. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  357. data/test/migrations/duplicate/3_foo.rb +0 -7
  358. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  359. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  360. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  361. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  362. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  363. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  364. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  365. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  366. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  367. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  368. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  369. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  370. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  371. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  372. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  373. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  374. data/test/models/author.rb +0 -151
  375. data/test/models/auto_id.rb +0 -4
  376. data/test/models/binary.rb +0 -2
  377. data/test/models/bird.rb +0 -9
  378. data/test/models/book.rb +0 -4
  379. data/test/models/categorization.rb +0 -5
  380. data/test/models/category.rb +0 -34
  381. data/test/models/citation.rb +0 -6
  382. data/test/models/club.rb +0 -13
  383. data/test/models/column_name.rb +0 -3
  384. data/test/models/comment.rb +0 -29
  385. data/test/models/company.rb +0 -173
  386. data/test/models/company_in_module.rb +0 -78
  387. data/test/models/computer.rb +0 -3
  388. data/test/models/contact.rb +0 -16
  389. data/test/models/contract.rb +0 -5
  390. data/test/models/course.rb +0 -3
  391. data/test/models/customer.rb +0 -73
  392. data/test/models/default.rb +0 -2
  393. data/test/models/developer.rb +0 -101
  394. data/test/models/edge.rb +0 -5
  395. data/test/models/entrant.rb +0 -3
  396. data/test/models/essay.rb +0 -3
  397. data/test/models/event.rb +0 -3
  398. data/test/models/event_author.rb +0 -8
  399. data/test/models/face.rb +0 -7
  400. data/test/models/guid.rb +0 -2
  401. data/test/models/interest.rb +0 -5
  402. data/test/models/invoice.rb +0 -4
  403. data/test/models/item.rb +0 -7
  404. data/test/models/job.rb +0 -5
  405. data/test/models/joke.rb +0 -3
  406. data/test/models/keyboard.rb +0 -3
  407. data/test/models/legacy_thing.rb +0 -3
  408. data/test/models/line_item.rb +0 -3
  409. data/test/models/man.rb +0 -9
  410. data/test/models/matey.rb +0 -4
  411. data/test/models/member.rb +0 -12
  412. data/test/models/member_detail.rb +0 -5
  413. data/test/models/member_type.rb +0 -3
  414. data/test/models/membership.rb +0 -9
  415. data/test/models/minimalistic.rb +0 -2
  416. data/test/models/mixed_case_monkey.rb +0 -3
  417. data/test/models/movie.rb +0 -5
  418. data/test/models/order.rb +0 -4
  419. data/test/models/organization.rb +0 -6
  420. data/test/models/owner.rb +0 -5
  421. data/test/models/parrot.rb +0 -22
  422. data/test/models/person.rb +0 -16
  423. data/test/models/pet.rb +0 -5
  424. data/test/models/pirate.rb +0 -80
  425. data/test/models/polymorphic_design.rb +0 -3
  426. data/test/models/polymorphic_price.rb +0 -3
  427. data/test/models/post.rb +0 -102
  428. data/test/models/price_estimate.rb +0 -3
  429. data/test/models/project.rb +0 -30
  430. data/test/models/reader.rb +0 -4
  431. data/test/models/reference.rb +0 -4
  432. data/test/models/reply.rb +0 -46
  433. data/test/models/ship.rb +0 -19
  434. data/test/models/ship_part.rb +0 -7
  435. data/test/models/sponsor.rb +0 -4
  436. data/test/models/subject.rb +0 -4
  437. data/test/models/subscriber.rb +0 -8
  438. data/test/models/subscription.rb +0 -4
  439. data/test/models/tag.rb +0 -7
  440. data/test/models/tagging.rb +0 -10
  441. data/test/models/task.rb +0 -3
  442. data/test/models/tee.rb +0 -4
  443. data/test/models/tie.rb +0 -4
  444. data/test/models/topic.rb +0 -80
  445. data/test/models/toy.rb +0 -6
  446. data/test/models/treasure.rb +0 -8
  447. data/test/models/vertex.rb +0 -9
  448. data/test/models/warehouse_thing.rb +0 -5
  449. data/test/models/zine.rb +0 -3
  450. data/test/schema/mysql_specific_schema.rb +0 -31
  451. data/test/schema/postgresql_specific_schema.rb +0 -114
  452. data/test/schema/schema.rb +0 -550
  453. data/test/schema/schema2.rb +0 -6
  454. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -3,16 +3,17 @@ module ActiveRecord
3
3
  # == What is Optimistic Locking
4
4
  #
5
5
  # Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of
6
- # conflicts with the data. It does this by checking whether another process has made changes to a record since
7
- # it was opened, an ActiveRecord::StaleObjectError is thrown if that has occurred and the update is ignored.
6
+ # conflicts with the data. It does this by checking whether another process has made changes to a record since
7
+ # it was opened, an <tt>ActiveRecord::StaleObjectError</tt> exception is thrown if that has occurred
8
+ # and the update is ignored.
8
9
  #
9
- # Check out ActiveRecord::Locking::Pessimistic for an alternative.
10
+ # Check out <tt>ActiveRecord::Locking::Pessimistic</tt> for an alternative.
10
11
  #
11
12
  # == Usage
12
13
  #
13
- # Active Records support optimistic locking if the field <tt>lock_version</tt> is present. Each update to the
14
- # record increments the lock_version column and the locking facilities ensure that records instantiated twice
15
- # will let the last one saved raise a StaleObjectError if the first was also updated. Example:
14
+ # Active Records support optimistic locking if the field +lock_version+ is present. Each update to the
15
+ # record increments the +lock_version+ column and the locking facilities ensure that records instantiated twice
16
+ # will let the last one saved raise a +StaleObjectError+ if the first was also updated. Example:
16
17
  #
17
18
  # p1 = Person.find(1)
18
19
  # p2 = Person.find(1)
@@ -23,7 +24,7 @@ module ActiveRecord
23
24
  # p2.first_name = "should fail"
24
25
  # p2.save # Raises a ActiveRecord::StaleObjectError
25
26
  #
26
- # Optimistic locking will also check for stale data when objects are destroyed. Example:
27
+ # Optimistic locking will also check for stale data when objects are destroyed. Example:
27
28
  #
28
29
  # p1 = Person.find(1)
29
30
  # p2 = Person.find(1)
@@ -36,25 +37,20 @@ module ActiveRecord
36
37
  # You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
37
38
  # or otherwise apply the business logic needed to resolve the conflict.
38
39
  #
39
- # You must ensure that your database schema defaults the lock_version column to 0.
40
+ # This locking mechanism will function inside a single Ruby process. To make it work across all
41
+ # web requests, the recommended approach is to add +lock_version+ as a hidden field to your form.
42
+ #
43
+ # You must ensure that your database schema defaults the +lock_version+ column to 0.
40
44
  #
41
45
  # This behavior can be turned off by setting <tt>ActiveRecord::Base.lock_optimistically = false</tt>.
42
- # To override the name of the lock_version column, invoke the <tt>set_locking_column</tt> method.
46
+ # To override the name of the +lock_version+ column, invoke the <tt>set_locking_column</tt> method.
43
47
  # This method uses the same syntax as <tt>set_table_name</tt>
44
48
  module Optimistic
45
- def self.included(base) #:nodoc:
46
- base.extend ClassMethods
47
-
48
- base.cattr_accessor :lock_optimistically, :instance_writer => false
49
- base.lock_optimistically = true
50
-
51
- base.alias_method_chain :update, :lock
52
- base.alias_method_chain :destroy, :lock
53
- base.alias_method_chain :attributes_from_column_definition, :lock
49
+ extend ActiveSupport::Concern
54
50
 
55
- class << base
56
- alias_method :locking_column=, :set_locking_column
57
- end
51
+ included do
52
+ cattr_accessor :lock_optimistically, :instance_writer => false
53
+ self.lock_optimistically = true
58
54
  end
59
55
 
60
56
  def locking_enabled? #:nodoc:
@@ -62,69 +58,62 @@ module ActiveRecord
62
58
  end
63
59
 
64
60
  private
65
- def attributes_from_column_definition_with_lock
66
- result = attributes_from_column_definition_without_lock
67
-
68
- # If the locking column has no default value set,
69
- # start the lock version at zero. Note we can't use
70
- # locking_enabled? at this point as @attributes may
71
- # not have been initialized yet
72
-
73
- if lock_optimistically && result.include?(self.class.locking_column)
74
- result[self.class.locking_column] ||= 0
75
- end
76
-
77
- return result
61
+ def increment_lock
62
+ lock_col = self.class.locking_column
63
+ previous_lock_value = send(lock_col).to_i
64
+ send(lock_col + '=', previous_lock_value + 1)
78
65
  end
79
66
 
80
- def update_with_lock(attribute_names = @attributes.keys) #:nodoc:
81
- return update_without_lock(attribute_names) unless locking_enabled?
67
+ def update(attribute_names = @attributes.keys) #:nodoc:
68
+ return super unless locking_enabled?
82
69
  return 0 if attribute_names.empty?
83
70
 
84
71
  lock_col = self.class.locking_column
85
- previous_value = send(lock_col).to_i
86
- send(lock_col + '=', previous_value + 1)
72
+ previous_lock_value = send(lock_col).to_i
73
+ increment_lock
87
74
 
88
75
  attribute_names += [lock_col]
89
76
  attribute_names.uniq!
90
77
 
91
78
  begin
92
- affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking")
93
- UPDATE #{self.class.quoted_table_name}
94
- SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false, attribute_names))}
95
- WHERE #{self.class.primary_key} = #{quote_value(id)}
96
- AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)}
97
- end_sql
79
+ relation = self.class.unscoped
80
+
81
+ stmt = relation.where(
82
+ relation.table[self.class.primary_key].eq(id).and(
83
+ relation.table[lock_col].eq(quote_value(previous_lock_value, self.class.columns_hash[lock_col]))
84
+ )
85
+ ).arel.compile_update(arel_attributes_values(false, false, attribute_names))
86
+
87
+ affected_rows = connection.update stmt
98
88
 
99
89
  unless affected_rows == 1
100
- raise ActiveRecord::StaleObjectError, "Attempted to update a stale object: #{self.class.name}"
90
+ raise ActiveRecord::StaleObjectError.new(self, "update")
101
91
  end
102
92
 
103
93
  affected_rows
104
94
 
105
95
  # If something went wrong, revert the version.
106
96
  rescue Exception
107
- send(lock_col + '=', previous_value)
97
+ send(lock_col + '=', previous_lock_value)
108
98
  raise
109
99
  end
110
100
  end
111
101
 
112
- def destroy_with_lock #:nodoc:
113
- return destroy_without_lock unless locking_enabled?
102
+ def destroy #:nodoc:
103
+ return super unless locking_enabled?
104
+
105
+ destroy_associations
114
106
 
115
- unless new_record?
107
+ if persisted?
108
+ table = self.class.arel_table
116
109
  lock_col = self.class.locking_column
117
- previous_value = send(lock_col).to_i
110
+ predicate = table[self.class.primary_key].eq(id).
111
+ and(table[lock_col].eq(send(lock_col).to_i))
118
112
 
119
- affected_rows = connection.delete(
120
- "DELETE FROM #{self.class.quoted_table_name} " +
121
- "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id} " +
122
- "AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)}",
123
- "#{self.class.name} Destroy"
124
- )
113
+ affected_rows = self.class.unscoped.where(predicate).delete_all
125
114
 
126
115
  unless affected_rows == 1
127
- raise ActiveRecord::StaleObjectError, "Attempted to delete a stale object: #{self.class.name}"
116
+ raise ActiveRecord::StaleObjectError.new(self, "destroy")
128
117
  end
129
118
  end
130
119
 
@@ -135,29 +124,31 @@ module ActiveRecord
135
124
  module ClassMethods
136
125
  DEFAULT_LOCKING_COLUMN = 'lock_version'
137
126
 
138
- def self.extended(base)
139
- class <<base
140
- alias_method_chain :update_counters, :lock
141
- end
142
- end
143
-
144
- # Is optimistic locking enabled for this table? Returns true if the
145
- # +lock_optimistically+ flag is set to true (which it is, by default)
146
- # and the table includes the +locking_column+ column (defaults to
147
- # +lock_version+).
127
+ # Returns true if the +lock_optimistically+ flag is set to true
128
+ # (which it is, by default) and the table includes the
129
+ # +locking_column+ column (defaults to +lock_version+).
148
130
  def locking_enabled?
149
131
  lock_optimistically && columns_hash[locking_column]
150
132
  end
151
133
 
134
+ def locking_column=(value)
135
+ @original_locking_column = @locking_column if defined?(@locking_column)
136
+ @locking_column = value.to_s
137
+ end
138
+
152
139
  # Set the column to use for optimistic locking. Defaults to +lock_version+.
153
140
  def set_locking_column(value = nil, &block)
154
- define_attr_method :locking_column, value, &block
155
- value
141
+ deprecated_property_setter :locking_column, value, block
156
142
  end
157
143
 
158
144
  # The version column used for optimistic locking. Defaults to +lock_version+.
159
145
  def locking_column
160
- reset_locking_column
146
+ reset_locking_column unless defined?(@locking_column)
147
+ @locking_column
148
+ end
149
+
150
+ def original_locking_column #:nodoc:
151
+ deprecated_original_property_getter :locking_column
161
152
  end
162
153
 
163
154
  # Quote the column name used for optimistic locking.
@@ -167,14 +158,26 @@ module ActiveRecord
167
158
 
168
159
  # Reset the column used for optimistic locking back to the +lock_version+ default.
169
160
  def reset_locking_column
170
- set_locking_column DEFAULT_LOCKING_COLUMN
161
+ self.locking_column = DEFAULT_LOCKING_COLUMN
171
162
  end
172
163
 
173
164
  # Make sure the lock version column gets updated when counters are
174
165
  # updated.
175
- def update_counters_with_lock(id, counters)
166
+ def update_counters(id, counters)
176
167
  counters = counters.merge(locking_column => 1) if locking_enabled?
177
- update_counters_without_lock(id, counters)
168
+ super
169
+ end
170
+
171
+ # If the locking column has no default value set,
172
+ # start the lock version at zero. Note we can't use
173
+ # <tt>locking_enabled?</tt> at this point as
174
+ # <tt>@attributes</tt> may not have been initialized yet.
175
+ def initialize_attributes(attributes, options = {}) #:nodoc:
176
+ if attributes.key?(locking_column) && lock_optimistically
177
+ attributes[locking_column] ||= 0
178
+ end
179
+
180
+ attributes
178
181
  end
179
182
  end
180
183
  end
@@ -3,30 +3,30 @@ module ActiveRecord
3
3
  # Locking::Pessimistic provides support for row-level locking using
4
4
  # SELECT ... FOR UPDATE and other lock types.
5
5
  #
6
- # Pass <tt>:lock => true</tt> to ActiveRecord::Base.find to obtain an exclusive
6
+ # Pass <tt>:lock => true</tt> to <tt>ActiveRecord::Base.find</tt> to obtain an exclusive
7
7
  # lock on the selected rows:
8
8
  # # select * from accounts where id=1 for update
9
9
  # Account.find(1, :lock => true)
10
10
  #
11
11
  # Pass <tt>:lock => 'some locking clause'</tt> to give a database-specific locking clause
12
- # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'.
12
+ # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. Example:
13
13
  #
14
- # Example:
15
14
  # Account.transaction do
16
15
  # # select * from accounts where name = 'shugo' limit 1 for update
17
- # shugo = Account.find(:first, :conditions => "name = 'shugo'", :lock => true)
18
- # yuko = Account.find(:first, :conditions => "name = 'yuko'", :lock => true)
16
+ # shugo = Account.where("name = 'shugo'").lock(true).first
17
+ # yuko = Account.where("name = 'yuko'").lock(true).first
19
18
  # shugo.balance -= 100
20
19
  # shugo.save!
21
20
  # yuko.balance += 100
22
21
  # yuko.save!
23
22
  # end
24
23
  #
25
- # You can also use ActiveRecord::Base#lock! method to lock one record by id.
24
+ # You can also use <tt>ActiveRecord::Base#lock!</tt> method to lock one record by id.
26
25
  # This may be better if you don't need to lock every row. Example:
26
+ #
27
27
  # Account.transaction do
28
28
  # # select * from accounts where ...
29
- # accounts = Account.find(:all, :conditions => ...)
29
+ # accounts = Account.where(...).all
30
30
  # account1 = accounts.detect { |account| ... }
31
31
  # account2 = accounts.detect { |account| ... }
32
32
  # # select * from accounts where id=? for update
@@ -38,18 +38,40 @@ module ActiveRecord
38
38
  # account2.save!
39
39
  # end
40
40
  #
41
+ # You can start a transaction and acquire the lock in one go by calling
42
+ # <tt>with_lock</tt> with a block. The block is called from within
43
+ # a transaction, the object is already locked. Example:
44
+ #
45
+ # account = Account.first
46
+ # account.with_lock do
47
+ # # This block is called within a transaction,
48
+ # # account is already locked.
49
+ # account.balance -= 100
50
+ # account.save!
51
+ # end
52
+ #
41
53
  # Database-specific information on row locking:
42
54
  # MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
43
- # PostgreSQL: http://www.postgresql.org/docs/8.1/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
55
+ # PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
44
56
  module Pessimistic
45
57
  # Obtain a row lock on this record. Reloads the record to obtain the requested
46
58
  # lock. Pass an SQL locking clause to append the end of the SELECT statement
47
- # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
59
+ # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
48
60
  # the locked record.
49
61
  def lock!(lock = true)
50
- reload(:lock => lock) unless new_record?
62
+ reload(:lock => lock) if persisted?
51
63
  self
52
64
  end
65
+
66
+ # Wraps the passed block in a transaction, locking the object
67
+ # before yielding. You pass can the SQL locking clause
68
+ # as argument (see <tt>lock!</tt>).
69
+ def with_lock(lock = true)
70
+ transaction do
71
+ lock!(lock)
72
+ yield
73
+ end
74
+ end
53
75
  end
54
76
  end
55
77
  end
@@ -0,0 +1,72 @@
1
+ module ActiveRecord
2
+ class LogSubscriber < ActiveSupport::LogSubscriber
3
+ def self.runtime=(value)
4
+ Thread.current["active_record_sql_runtime"] = value
5
+ end
6
+
7
+ def self.runtime
8
+ Thread.current["active_record_sql_runtime"] ||= 0
9
+ end
10
+
11
+ def self.reset_runtime
12
+ rt, self.runtime = runtime, 0
13
+ rt
14
+ end
15
+
16
+ def initialize
17
+ super
18
+ @odd_or_even = false
19
+ end
20
+
21
+ def sql(event)
22
+ self.class.runtime += event.duration
23
+ return unless logger.debug?
24
+
25
+ payload = event.payload
26
+
27
+ return if 'SCHEMA' == payload[:name]
28
+
29
+ name = '%s (%.1fms)' % [payload[:name], event.duration]
30
+ sql = payload[:sql].squeeze(' ')
31
+ binds = nil
32
+
33
+ unless (payload[:binds] || []).empty?
34
+ binds = " " + payload[:binds].map { |col,v|
35
+ if col
36
+ [col.name, v]
37
+ else
38
+ [nil, v]
39
+ end
40
+ }.inspect
41
+ end
42
+
43
+ if odd?
44
+ name = color(name, CYAN, true)
45
+ sql = color(sql, nil, true)
46
+ else
47
+ name = color(name, MAGENTA, true)
48
+ end
49
+
50
+ debug " #{name} #{sql}#{binds}"
51
+ end
52
+
53
+ def identity(event)
54
+ return unless logger.debug?
55
+
56
+ name = color(event.payload[:name], odd? ? CYAN : MAGENTA, true)
57
+ line = odd? ? color(event.payload[:line], nil, true) : event.payload[:line]
58
+
59
+ debug " #{name} #{line}"
60
+ end
61
+
62
+ def odd?
63
+ @odd_or_even = !@odd_or_even
64
+ end
65
+
66
+ def logger
67
+ ActiveRecord::Base.logger
68
+ end
69
+ end
70
+ end
71
+
72
+ ActiveRecord::LogSubscriber.attach_to :active_record
@@ -0,0 +1,105 @@
1
+ module ActiveRecord
2
+ class Migration
3
+ # <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
4
+ # a migration and knows how to reverse those commands. The CommandRecorder
5
+ # knows how to invert the following commands:
6
+ #
7
+ # * add_column
8
+ # * add_index
9
+ # * add_timestamps
10
+ # * create_table
11
+ # * remove_timestamps
12
+ # * rename_column
13
+ # * rename_index
14
+ # * rename_table
15
+ class CommandRecorder
16
+ attr_accessor :commands, :delegate
17
+
18
+ def initialize(delegate = nil)
19
+ @commands = []
20
+ @delegate = delegate
21
+ end
22
+
23
+ # record +command+. +command+ should be a method name and arguments.
24
+ # For example:
25
+ #
26
+ # recorder.record(:method_name, [:arg1, :arg2])
27
+ def record(*command)
28
+ @commands << command
29
+ end
30
+
31
+ # Returns a list that represents commands that are the inverse of the
32
+ # commands stored in +commands+. For example:
33
+ #
34
+ # recorder.record(:rename_table, [:old, :new])
35
+ # recorder.inverse # => [:rename_table, [:new, :old]]
36
+ #
37
+ # This method will raise an +IrreversibleMigration+ exception if it cannot
38
+ # invert the +commands+.
39
+ def inverse
40
+ @commands.reverse.map { |name, args|
41
+ method = :"invert_#{name}"
42
+ raise IrreversibleMigration unless respond_to?(method, true)
43
+ send(method, args)
44
+ }
45
+ end
46
+
47
+ def respond_to?(*args) # :nodoc:
48
+ super || delegate.respond_to?(*args)
49
+ end
50
+
51
+ [:create_table, :change_table, :rename_table, :add_column, :remove_column, :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps, :change_column, :change_column_default].each do |method|
52
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
53
+ def #{method}(*args) # def create_table(*args)
54
+ record(:"#{method}", args) # record(:create_table, args)
55
+ end # end
56
+ EOV
57
+ end
58
+
59
+ private
60
+
61
+ def invert_create_table(args)
62
+ [:drop_table, [args.first]]
63
+ end
64
+
65
+ def invert_rename_table(args)
66
+ [:rename_table, args.reverse]
67
+ end
68
+
69
+ def invert_add_column(args)
70
+ [:remove_column, args.first(2)]
71
+ end
72
+
73
+ def invert_rename_index(args)
74
+ [:rename_index, [args.first] + args.last(2).reverse]
75
+ end
76
+
77
+ def invert_rename_column(args)
78
+ [:rename_column, [args.first] + args.last(2).reverse]
79
+ end
80
+
81
+ def invert_add_index(args)
82
+ table, columns, options = *args
83
+ index_name = options.try(:[], :name)
84
+ options_hash = index_name ? {:name => index_name} : {:column => columns}
85
+ [:remove_index, [table, options_hash]]
86
+ end
87
+
88
+ def invert_remove_timestamps(args)
89
+ [:add_timestamps, args]
90
+ end
91
+
92
+ def invert_add_timestamps(args)
93
+ [:remove_timestamps, args]
94
+ end
95
+
96
+ # Forwards any missing method call to the \target.
97
+ def method_missing(method, *args, &block)
98
+ @delegate.send(method, *args, &block)
99
+ rescue NoMethodError => e
100
+ raise e, e.message.sub(/ for #<.*$/, " via proxy for #{@delegate}")
101
+ end
102
+
103
+ end
104
+ end
105
+ end