usable 1.2.1 → 1.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e971571c1349c6977b3e0d8050536a2d1d75f76
4
- data.tar.gz: cc1dcf9e4678b7ae565e3a4e8bcb111b5253b853
3
+ metadata.gz: e880dacf65e19267ebe16ba66d5ec85759f8e17d
4
+ data.tar.gz: 7bd498ea658d2cff0b13207a27d98df96e740442
5
5
  SHA512:
6
- metadata.gz: c2c23c4aefe50a4cec3a8ee7232ecaf7f84f5f1d71a5f1f33fe7212cb08581c4301ebd6143fa3ccaa839691c0f2ce171d88d39af9bb6f0ff035733c07d6d3bec
7
- data.tar.gz: 5cce2ae60678d9ce8cd1ac1230d84c27d53ca77338cedc31cd5ab3fbb676d0bb840cf1ea8e7cff3edaa1b983172d319655292d7a76091cc3fda2661c9e6179b3
6
+ metadata.gz: 8b4f4ce971e0f34b25190b69f67c1df97fe6e9b8ce1960d4ce10b2ec5e988f1b74187a0ef9882553be2a4aedd179220534d8e822a0f57c1d5cd068a1862e824f
7
+ data.tar.gz: fd4f4fdf322c535abea6f95d50ac02dcf3731f3aaa153b12729d2d37acd50b0ee04dca8432132c0adc083760b482e4f42cd081cd9dbc7ea4fc9684034752d017
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Usable [![Gem Version](https://badge.fury.io/rb/usable.svg)](http://badge.fury.io/rb/usable) [![Build Status](https://travis-ci.org/ridiculous/usable.svg)](https://travis-ci.org/ridiculous/usable) [![Code Climate](https://codeclimate.com/github/ridiculous/usable/badges/gpa.svg)](https://codeclimate.com/github/ridiculous/usable)
2
2
 
3
- A simple way to mount and configure your modules. Usable gives you control over which methods are included, and a simple
3
+ An elegant way to mount and configure your modules. Usable gives you control over which methods are included, and a simple
4
4
  interface to help you call dynamic methods with confidence.
5
5
 
6
6
  ```ruby
@@ -31,7 +31,21 @@ model = Model.new
31
31
  model.save_version # => "Saving up to 10 versions to custom_versions"
32
32
  model.destroy_version # => NoMethodError: undefined method `destroy_version' for #<Model:...
33
33
  ```
34
- `Model` now has a `#save_versions` method but no `#destroy_version` method.
34
+ `Model` now has a `#save_versions` method but no `#destroy_version` method. Usable has effectively mixed in the given module
35
+ using `include`. Ruby 2+ offers the `prepend` method, which can be used instead by specifying it as the `:method` option:
36
+
37
+ ```ruby
38
+ Model.usable VersionMixin, method: :prepend
39
+ ```
40
+
41
+ Usable reserves the `:only` and `:method` keys. All other keys in the given hash are defined as config settings.
42
+ If you really want to define a config on the target class with one of these names, you can simply define them in the block:
43
+
44
+ ```ruby
45
+ Model.usable VersionMixin, only: [:save_version] do |config|
46
+ config.only = "Will be set on `Model.usable_config.only`"
47
+ end
48
+ ```
35
49
 
36
50
  ## Confidently calling methods
37
51
 
data/bin/console CHANGED
@@ -54,11 +54,19 @@ class Model
54
54
  end
55
55
  end
56
56
 
57
+ module PersistenceOverride
58
+ def save
59
+ 'nope'
60
+ end
61
+ end
62
+
57
63
  class Example
58
64
  extend Usable
59
65
  usable Mixin, only: [:name, :from_spec]
60
66
  end
61
67
 
68
+ Model.usable PersistenceOverride, method: 'prepend'
69
+
62
70
  require "irb"
63
71
 
64
72
  IRB.start
@@ -1,35 +1,62 @@
1
1
  module Usable
2
2
  class ModExtender
3
3
  attr_reader :name
4
- attr_accessor :copy, :mod, :config
4
+ attr_accessor :copy, :mod, :options
5
5
 
6
- def initialize(mod, config = OpenStruct.new)
6
+ def initialize(mod, options = {})
7
7
  @mod = mod
8
+ @options = options
9
+ @options[:method] ||= :include
8
10
  if has_spec?
9
11
  @copy = mod.const_get(:UsableSpec).dup
10
12
  @name = "#{mod.name}UsableSpec"
11
13
  else
12
- @copy = mod.dup
14
+ @copy = mod.dup
13
15
  @name = mod.name
14
16
  end
15
- @config = config
16
17
  end
17
18
 
18
- # @note Destructive
19
19
  def call
20
20
  override
21
21
  copy
22
22
  end
23
23
 
24
+ # @note Destructive, as it changes the dup'd mod
24
25
  def override
25
- unwanted = config.only ? copy.instance_methods - Array(config.only) : []
26
+ unwanted = options[:only] ? copy.instance_methods - Array(options[:only]) : []
26
27
  unwanted.each do |method_name|
27
28
  copy.send :remove_method, method_name
28
29
  end
29
30
  end
30
31
 
32
+ # @description Directly include a module whose methods you want made available in +usable_config.available_methods+
33
+ # Gives the module a name when including so that it shows up properly in the list of ancestors
34
+ def use!(target)
35
+ const_name = "#{mod_name}Used"
36
+ override
37
+ target.send :remove_const, const_name if target.const_defined? const_name, false
38
+ target.const_set const_name, copy
39
+ target.usable_config.modules << copy
40
+ target.send options[:method], copy
41
+ end
42
+
43
+ # @description Sends the method to the target with the original module
44
+ def use_original!(target)
45
+ return unless has_spec?
46
+ target.usable_config.modules << mod
47
+ target.send options[:method], mod
48
+ end
49
+
31
50
  def has_spec?
32
51
  mod.const_defined?(:UsableSpec)
33
52
  end
53
+
54
+ def mod_name
55
+ if name
56
+ name.split('::').last
57
+ else
58
+ "UsableMod#{Time.now.strftime('%s')}"
59
+ end
60
+ end
34
61
  end
35
62
  end
@@ -1,3 +1,3 @@
1
1
  module Usable
2
- VERSION = "1.2.1".freeze
2
+ VERSION = "1.3.0".freeze
3
3
  end
data/lib/usable.rb CHANGED
@@ -5,48 +5,43 @@ require 'usable/mod_extender'
5
5
  require 'usable/config'
6
6
 
7
7
  module Usable
8
-
9
8
  def usable_config
10
9
  @usable_config ||= Config.new
11
10
  end
12
11
  attr_writer :usable_config
13
12
 
14
13
  # @description Configures the +available_methods+ of a module using the given options or block and then includes it on
15
- # the target class. Checks if there is a module named UsableSpec within the given mods namespace and uses the instance of
14
+ # the target class. Checks if there is a module named UsableSpec within the given mods namespace and uses the instance
16
15
  # methods of that as the +available_methods+
17
16
  #
18
17
  # @example
19
18
  #
20
19
  # class Example
21
20
  # extend Usable
22
- # usable VersionKit, only: :save_version
21
+ # usable Mixin, only: [:foo, :bar] do |config|
22
+ # config.baz = "Available as `Example.usable_config.baz`"
23
+ # end
23
24
  # end
24
25
  #
25
26
  # @note Hides methods
26
- # @note We include the primary mod when there is a UsableSpec set because any instance method defined on the mod are not
27
- # configurable and should therefore takes precedence over those defined in the UsableSpec
27
+ # @note We include the primary mod when there is a UsableSpec set because any instance methods defined on the mod are
28
+ # not configurable and should therefore takes precedence over those defined in the UsableSpec
29
+ #
30
+ # @param [Module] mod
31
+ # @param [Hash] options Customize the extension of the module as well as define config settings on the target
32
+ # @option [Array,Symbol] :only Limit which methods are copied from the module
33
+ # @option [String,Symbol] :method (:include) The method to use for including the module
28
34
  # @return [ModExtender] containing the original and modified module
29
35
  def usable(mod, options = {})
36
+ usable_options = { only: options.delete(:only), method: options.delete(:method) }
30
37
  options.each { |k, v| usable_config.public_send "#{k}=", v }
31
38
  yield usable_config if block_given?
32
- mod_ext = ModExtender.new mod, usable_config
33
- usable! mod_ext
34
- usable! mod if mod_ext.has_spec?
39
+ mod_ext = ModExtender.new mod, usable_options
40
+ mod_ext.use! self
41
+ mod_ext.use_original! self
35
42
  mod_ext
36
43
  end
37
44
 
38
- # @description Directly include a module whose methods you want made available in +usable_config.available_methods+
39
- # Gives the module a name when including so that it shows up properly in the list of ancestors
40
- def usable!(mod)
41
- mod_name = mod.name ? mod.name.split('::').last : "UsableMod#{Time.now.strftime('%s')}"
42
- const_name = "#{mod_name}Used"
43
- mod = mod.call if mod.respond_to? :call
44
- remove_const const_name if const_defined? const_name, false
45
- const_set const_name, mod
46
- usable_config.modules << mod
47
- send :include, mod
48
- end
49
-
50
45
  # @return [Method] bound to the given -context-
51
46
  def usable_method(context, method_name)
52
47
  usable_config.available_methods[method_name].bind(context)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: usable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Buckley
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-02-16 00:00:00.000000000 Z
11
+ date: 2016-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,6 +67,7 @@ extensions: []
67
67
  extra_rdoc_files: []
68
68
  files:
69
69
  - ".gitignore"
70
+ - ".rspec"
70
71
  - ".ruby-gemset"
71
72
  - ".ruby-version"
72
73
  - ".travis.yml"