README.md in prependers-0.3.0 vs README.md in prependers-1.0.0
- old
+ new
@@ -16,26 +16,25 @@
```console
$ bundle
```
-
Or install it yourself as:
```console
$ gem install prependers
```
## Usage
-To define a prepender manually, simply include the `Prependers::Prepender.new` module. For instance,
+To define a prepender manually, simply include the `Prependers::Prepender[]` module. For instance,
if you have installed an `animals` gem and you want to extend the `Animals::Dog` class, you can
define a module like the following:
```ruby
module Animals::Dog::AddBarking
- include Prependers::Prepender.new
+ include Prependers::Prepender[]
def bark
puts 'Woof!'
end
end
@@ -48,11 +47,11 @@
If you want to extend a module's class methods, you can define a `ClassMethods` module in your
prepender:
```ruby
module Animals::Dog::AddFamily
- include Prependers::Prepender.new
+ include Prependers::Prepender[]
module ClassMethods
def family
puts 'Canids'
end
@@ -60,17 +59,104 @@
end
Animals::Dog.family # => 'Canids'
```
-As you can see, the `ClassMethods` module has automagically been `prepend`ed to the `Animals::Dog`'s
+As you can see, the `ClassMethods` module has automagically been `prepend`ed to `Animals::Dog`'s
singleton class.
+### Using a namespace
+
+It can be useful to have a prefix namespace for your prependers. That way, you don't have to worry
+about accidentally overriding any vendor modules. This is actually the recommended way to define
+your prependers.
+
+You can accomplish this by passing the `:namespace` option when including `Prependers::Prepender`:
+
+```ruby
+module MyApp
+ module Animals
+ module Dog
+ module AddBarking
+ include Prependers::Prepender[namespace: MyApp]
+
+ def bark
+ puts 'Woof!'
+ end
+ end
+ end
+ end
+end
+```
+
+### Verifying original sources
+
+One issue you may run into when extending third-party code is that, when the original implementation
+is updated, it's not always obvious whether you have to update any of your extensions.
+
+Prependers make this a bit easier with the concept of original source verification: you can compute
+a SHA1 hash of the original implementation, store it along with your prepender, and then verify it
+against the current hash when your application loads. If the original source changes, you get an
+error asking you to ensure your prepender is still relevant.
+
+To use original source verification in your prependers, pass the `:verify` option:
+
+```ruby
+module Animals::Dog::AddBarking
+ include Prependers::Prepender[verify: nil]
+
+ # ...
+end
+```
+
+When you load your application now, you will get an error with instructions on how to set the proper
+hash:
+
+```
+Prependers::OutdatedPrependerError:
+ You have not defined an original hash for Animals::Dog in Animals::Dog::AddBarking.
+
+ You can define the hash by updating your include statement as follows:
+
+ include Prependers::Prepender[verify: 'f7175533215c39f3f3328aa5829ac6b1bb168218']
+```
+
+At this point, you should update your prepender with the correct hash:
+
+```ruby
+module Animals::Dog::AddBarking
+ include Prependers::Prepender[verify: 'f7175533215c39f3f3328aa5829ac6b1bb168218']
+
+ # ...
+end
+```
+
+Now, when the underlying implementation of `Animals::Dog` changes because of a dependency update or
+other reasons, Prependers will raise an error such as the following:
+
+```
+Prependers::OutdatedPrependerError:
+ The stored hash for Animals::Dog in Animals::Dog::AddBarking is
+ f7175533215c39f3f3328aa5829ac6b1bb168218, but the current hash is
+ 2f05682e4f46b509c23a8418d9427a9eeaa8a79e instead.
+
+ This most likely means that the original source has changed.
+
+ Check that your prepender is still valid, then update the stored hash:
+
+ include Prependers::Prepender[verify: '2f05682e4f46b509c23a8418d9427a9eeaa8a79e']
+```
+
+Original source verification also works when a module is defined in multiple locations.
+
+*NOTE: Due to limitations in Ruby's API, it is not possible to use source verification with modules
+that don't define any methods. Prependers will raise an error if you try to do this.*
+
### Autoloading prependers
-If you don't want to include `Prependers::Prepender`, you can also autoload prependers from a path,
-they will be loaded in alphabetical order.
+If you don't want to include `Prependers::Prepender[]`, you can also autoload prependers from a
+path, they will be loaded in alphabetical order.
Here's the previous example, but with autoloading:
```ruby
# app/prependers/animals/dog/add_barking.rb
@@ -82,10 +168,13 @@
# somewhere in your initialization code
Prependers.load_paths(File.expand_path('app/prependers'))
```
+Note that, in order for autoprepending to work, the paths of your prependers must match the names
+of the prependers you defined.
+
You can pass multiple arguments to `#load_paths`, which is useful if you have subdirectories in
`app/prependers`:
```ruby
Prependers.load_paths(
@@ -93,53 +182,29 @@
File.expand_path('app/prependers/models'),
# ...
)
```
-Note that, in order for autoprepending to work, the paths of your prependers must match the names
-of the prependers you defined.
+You can pass the `:namespace` option to `#load_paths` to have it forwarded to all prependers:
-### Using a namespace
-
-It can be useful to have a prefix namespace for your prependers. That way, you don't have to worry
-about accidentally overriding any vendor modules. This is actually the recommended way to define
-your prependers.
-
-You can accomplish this by passing an argument when including the `Prependers::Prepender` module:
-
```ruby
-module MyApp
- module Animals
- module Dog
- module AddBarking
- include Prependers::Prepender.new(MyApp)
-
- def bark
- puts 'Woof!'
- end
- end
- end
- end
-end
+Prependers.load_paths(
+ File.expand_path('app/prependers/controllers'),
+ File.expand_path('app/prependers/models'),
+ namespace: Acme,
+)
```
-If you use autoloading, you can pass the base namespace to `#load_paths`:
-
-```ruby
-Prependers.load_paths(File.expand_path('app/prependers'), namespace: MyApp)
-```
-
### Integrating with Rails
To use prependers in your Rails app, simply create them under `app/prependers/models`,
`app/prependers/controllers` etc. and add the following to your `config/application.rb`:
```ruby
Prependers.setup_for_rails
```
-If you want to use a namespace, just pass the `:namespace` option to `#setup_for_rails` and name
-your files and modules accordingly.
+`#setup_for_rails` accepts the same options as `#load_paths`.
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
the tests. You can also run `bin/console` for an interactive prompt that will allow you to