This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
augmentations / README.markdown
| 0078f6cf » | henrik | 2008-09-10 | 1 | # Augmentations | |
| 2 | |||||
| 3 | Too "fat" Rails models can be unmanageable. Also, sometimes you want to define or run the same methods in several different models. | ||||
| 4 | |||||
| 5 | *Augmentations* is a Rails plugin that provides a simple API for extending a model (or other class) with instance methods and class methods, as well as running class methods like `belongs_to` at extend time. | ||||
| 6 | |||||
| 7 | ## Rails model extensions | ||||
| 8 | |||||
| 9 | This plugin uses regular Ruby modules, but with some additions. | ||||
| 10 | |||||
| 11 | My [Rails model extensions](http://henrik.nyh.se/2008/02/rails-model-extensions) article gives details on how you can use modules to extend Rails models. In brief: | ||||
| 12 | |||||
| 13 | You define a module like | ||||
| 14 | |||||
| 15 | module Shared | ||||
| 16 | module Pingable | ||||
| 5c7e9e12 » | henrik | 2008-09-10 | 17 | # … | |
| 0078f6cf » | henrik | 2008-09-10 | 18 | end | |
| 19 | end | ||||
| 20 | |||||
| 21 | in `app/models/shared/pingable.rb`, or | ||||
| 22 | |||||
| 23 | module User | ||||
| 24 | module PasswordResetExtension | ||||
| 5c7e9e12 » | henrik | 2008-09-10 | 25 | # … | |
| 0078f6cf » | henrik | 2008-09-10 | 26 | end | |
| 27 | end | ||||
| 28 | |||||
| 29 | in `app/models/user/password_reset_extension.rb`. | ||||
| 30 | |||||
| 31 | |||||
| 32 | ## Old style | ||||
| 33 | |||||
| 34 | Without this plugin, you would then include them in models like | ||||
| 35 | |||||
| 36 | class User < ActiveRecord::Base | ||||
| 37 | include PasswordResetExtension, | ||||
| 38 | Shared::Pingable | ||||
| 39 | end | ||||
| 40 | |||||
| 41 | The `app/models/shared/pingable.rb` file could look something like | ||||
| 42 | |||||
| 43 | module Shared | ||||
| 44 | module Pingable | ||||
| 45 | |||||
| 46 | def an_instance_method | ||||
| 47 | # … | ||||
| 48 | end | ||||
| 49 | |||||
| 50 | def self.included(klass) | ||||
| 51 | klass.class_eval do | ||||
| 52 | belongs_to :ping | ||||
| 53 | |||||
| 54 | def self.a_class_method | ||||
| 55 | # … | ||||
| 56 | end | ||||
| 57 | end | ||||
| 58 | end | ||||
| 59 | |||||
| 60 | end | ||||
| 61 | end | ||||
| 62 | |||||
| 63 | I have some issues with this: | ||||
| 64 | |||||
| 65 | * There is too much boilerplate in the module, obscuring what you're actually adding. | ||||
| 66 | |||||
| 77fb517b » | henrik | 2008-11-19 | 67 | * Abusing the standard method `include` to not only add instance methods but also do stuff on the class level can be confusing. You could use `extend` as well, though this is more verbose. To get the `belongs_to`, you'd still need to use module hooks, or put another line of code in the model. | |
| 0078f6cf » | henrik | 2008-09-10 | 68 | ||
| 69 | * It looks different from how the code would look if defined in the model: the instance methods are in a different block of code than the class-level stuff – though you could get around this by putting everything in the `class_eval`. | ||||
| 70 | |||||
| 71 | |||||
| 72 | ## New style | ||||
| 73 | |||||
| 71188c1f » | henrik | 2008-09-10 | 74 | Modules are still used, as described above, but the API is improved. | |
| 0078f6cf » | henrik | 2008-09-10 | 75 | ||
| 76 | Use *Augmentations* like: | ||||
| 77 | |||||
| 78 | class User < ActiveRecord::Base | ||||
| 79 | augment Shared::Pingable, PasswordResetExtension | ||||
| 80 | end | ||||
| 81 | |||||
| 82 | With modules like | ||||
| 83 | |||||
| 84 | module Shared | ||||
| 85 | module Pingable | ||||
| 86 | augmentation do | ||||
| 87 | |||||
| 88 | belongs_to :ping | ||||
| 89 | |||||
| 90 | def self.a_class_method | ||||
| 91 | # … | ||||
| 92 | end | ||||
| 93 | |||||
| 94 | def an_instance_method | ||||
| 95 | # … | ||||
| 96 | end | ||||
| 97 | |||||
| 98 | end | ||||
| 99 | end | ||||
| 100 | end | ||||
| 101 | |||||
| 102 | What I like about this: | ||||
| 103 | |||||
| 104 | * A new method, `augment`, is used, rather than abusing `include`. | ||||
| 105 | |||||
| fa770f15 » | henrik | 2008-09-10 | 106 | * Less boilerplate. | |
| 0078f6cf » | henrik | 2008-09-10 | 107 | ||
| 108 | * Keeps the code for class and instances together, looking just like it would do in the model. You could achieve this with `included` and `class_eval` as mentioned above, but it would not have the other benefits. | ||||
| 109 | |||||
| 110 | * The plugin amounts to very little code and a straightforward implementation. It's basically lipstick on `included` and `class_eval`. | ||||
| 111 | |||||
| 112 | (If you want to weird things up in the name of fewer lines of code, the Ruby parser will accept | ||||
| 113 | |||||
| 114 | module Shared | ||||
| 115 | module Pingable augmentation do | ||||
| 116 | |||||
| 117 | … | ||||
| 118 | |||||
| 119 | end end | ||||
| 120 | end | ||||
| 121 | |||||
| 122 | too.) | ||||
| 123 | |||||
| 124 | |||||
| 125 | ## To-do | ||||
| 126 | |||||
| 127 | Add support for module arguments; something like | ||||
| 128 | |||||
| 129 | augment Shared::Pingable, :pong => false | ||||
| 130 | |||||
| 131 | |||||
| 132 | ## Credits | ||||
| 133 | |||||
| 134 | By [Henrik Nyh](http://henrik.nyh.se/) for [DanceJam](http://dancejam.com). | ||||








