usable 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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"