usable 1.4.0 → 2.0.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: d621f72fd2963cd0ed5e82ca9a52458a412ac982
4
- data.tar.gz: 870b80be3fa3fb74e178ad5204b806a78c37a3a8
3
+ metadata.gz: 248031af23fb6b13a611f3ad52aed2b485e13042
4
+ data.tar.gz: 7d43e66f04750393514a83e5cf6af8950aecd242
5
5
  SHA512:
6
- metadata.gz: 15e90259cd4528fbedd199d8b2024622d8b93ef4f534e65de55b5aae5ef11e694cdb30ed0d73a542fff333f5cba796dae6488b34118f22bae25e591d952a5ced
7
- data.tar.gz: 9bfb0cbe38beb7b8e5b7d76cbb8395cd02f1f552a8abe0417d908546b1df38ae186537888dfc9a9ebd78a63495ea4c97128423421091e4cb7e1a3ce8ba49db71
6
+ metadata.gz: f33b9468b3368318c1eb79d692e168a05de74378307e8c8006c162511f2d6636ebf9f0f186c16ea85f08e63e2217212e110a7edc0328069d9c3667c40ffb7201
7
+ data.tar.gz: ca0191741f597b8c6c948135cc121c906a36ea6586e5d1a3aea6ac36d3a6b645162eace8e908675788be19cca9d895135b646be6504ea5022494e7cac1f93296
data/README.md CHANGED
@@ -1,29 +1,33 @@
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
- An elegant way to mount and configure your modules. Usable gives you control over which methods are included, and a simple
4
- interface to help you call dynamic methods with confidence.
3
+ Usable provides an elegant way to mount and configure your modules. Class level settings can be configured on a per module basis,
4
+ available to both the module and including class. Allows you to include only the methods you want.
5
5
 
6
6
  ```ruby
7
7
  module VersionMixin
8
+ extend Usable
9
+ usables[:max_versions] = 25
10
+ usables[:table_name] = 'versions'
11
+
8
12
  def save_version
9
- "Saving up to #{self.class.usable_config.max_versions} versions to #{self.class.usable_config.table_name}"
13
+ "Saving up to #{usables.max_versions} versions to #{usables.table_name}"
10
14
  end
11
15
 
12
16
  def destroy_version
13
- "Deleting versions from #{self.class.usable_config.table_name}"
17
+ "Deleting versions from #{usables.table_name}"
14
18
  end
15
19
  end
16
20
 
17
21
  class Model
18
22
  extend Usable
19
23
 
20
- usable VersionMixin, only: :save_version do |config|
21
- config.max_versions = 10
22
- config.table_name = 'custom_versions'
24
+ usable VersionMixin, only: :save_version do
25
+ max_versions 10
26
+ table_name 'custom_versions'
23
27
  end
24
28
 
25
29
  def save
26
- self.class.usable_method(self, :save_version).call
30
+ usable_method(:save_version).call
27
31
  end
28
32
  end
29
33
 
@@ -38,8 +42,8 @@ using `include`. Ruby 2+ offers the `prepend` method, which can be used instead
38
42
  Model.usable VersionMixin, method: :prepend
39
43
  ```
40
44
 
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:
45
+ Usable reserves the `:only` and `:method` keys. All other keys in the given hash are defined as config settings. If you really
46
+ want to define a config on the target class with one of these names, you can simply define them in the block:
43
47
 
44
48
  ```ruby
45
49
  Model.usable VersionMixin, only: [:save_version] do |config|
@@ -50,13 +54,14 @@ end
50
54
  ## Confidently calling methods
51
55
 
52
56
  We should all be writing [confident code](http://www.confidentruby.com/), which is why you might want to call configurable
53
- methods through the `usable_method` class level function. Methods passed in with the `:only` option
57
+ methods through the `usable_method` class and instance method. Methods passed in with the `:only` option
54
58
  will _always_ return `nil` when called. Thus, the confidence.
55
59
 
56
60
  Here's the same example as above, rewritten to call methods through the Usable interface:
57
61
 
58
62
  ```ruby
59
63
  Model.usable_method(model, :save_version).call # => "Saving up to 10 versions to custom_versions"
64
+ model.usable_method(:save_version).call # => "Saving up to 10 versions to custom_versions"
60
65
  Model.usable_method(model, :destroy_version).call # => nil
61
66
  ```
62
67
 
data/bin/console CHANGED
@@ -12,15 +12,18 @@ require "usable"
12
12
 
13
13
  module VersionMixin
14
14
  def save_version
15
- "Saving up to #{self.class.usable_config.max_versions} versions to #{self.class.usable_config.table_name}"
15
+ "Saving up to #{usables.max_versions} versions to #{usables.table_name}"
16
16
  end
17
17
 
18
18
  def destroy_version
19
- "Deleting versions from #{self.class.usable_config.table_name}"
19
+ "Deleting versions from #{usables.table_name}"
20
20
  end
21
21
  end
22
22
 
23
23
  module Mixin
24
+ extend Usable
25
+ usables[:max_versions] = 20
26
+
24
27
  def name
25
28
  "defined by Mixin"
26
29
  end
@@ -44,13 +47,13 @@ end
44
47
  class Model
45
48
  extend Usable
46
49
 
47
- usable VersionMixin, only: :save_version do |config|
48
- config.max_versions = 10
49
- config.table_name = 'custom_versions'
50
+ usable VersionMixin, only: :save_version do
51
+ max_versions 10
52
+ table_name 'custom_versions'
50
53
  end
51
54
 
52
55
  def save
53
- self.class.usable_method(self, :save_version).call
56
+ usable_method(:save_version).call
54
57
  end
55
58
  end
56
59
 
@@ -60,10 +63,21 @@ module PersistenceOverride
60
63
  end
61
64
  end
62
65
 
66
+ module Nested
67
+ module Extension
68
+ def go
69
+ 'going'
70
+ end
71
+ end
72
+ end
73
+
63
74
  class Example
64
75
  extend Usable
65
76
  usable Mixin
66
- usable VersionMixin, max_versions: 10
77
+ usable VersionMixin do
78
+ max_versions 10
79
+ end
80
+ usable Nested::Extension
67
81
  end
68
82
 
69
83
  Model.usable PersistenceOverride, method: 'prepend'
data/lib/usable/config.rb CHANGED
@@ -1,27 +1,59 @@
1
1
  module Usable
2
- class Config < OpenStruct
3
- def modules
4
- @modules ||= []
2
+ class Config
3
+ # = Class
4
+ # Store and manage configuration settings. Keep methods to a minimum since this class relies on method_missing to read
5
+ # and write to the underlying @spec object
6
+ #
7
+
8
+ def available_methods
9
+ modules.each_with_object(Hash.new(Null.instance_method(:default_method))) do |mod, result|
10
+ mod.instance_methods.each do |method_name|
11
+ result[method_name] = mod.instance_method method_name
12
+ end
13
+ end
5
14
  end
6
15
 
7
16
  def add_module(mod)
8
17
  modules << mod
9
18
  end
10
19
 
11
- def available_methods
12
- modules.each_with_object(Hash.new(default_method)) do |mod, result|
13
- mod.instance_methods.each do |method_name|
14
- result[method_name] = mod.instance_method method_name
15
- end
20
+ def modules
21
+ @modules ||= []
22
+ end
23
+
24
+ def each(&block)
25
+ @spec.to_h.each(&block)
26
+ end
27
+
28
+ def spec(key, value = nil)
29
+ @spec ||= OpenStruct.new
30
+ if value
31
+ @spec[key.to_s.tr('=', '')] = value
32
+ else
33
+ @spec[key]
16
34
  end
17
35
  end
18
36
 
19
- def default_method
20
- Null.instance_method(:default_method)
37
+ def [](key)
38
+ spec key
39
+ end
40
+
41
+ def []=(key, val)
42
+ spec key, val
43
+ end
44
+
45
+ def method_missing(method_name, *args)
46
+ spec method_name, *args
47
+ rescue
48
+ super
49
+ end
50
+
51
+ def respond_to_missing?(method_name, _private = false)
52
+ method_name.to_s.end_with?('=') || spec.respond_to?(method_name)
21
53
  end
22
54
 
23
55
  module Null
24
- def default_method(*, &block)
56
+ def default_method(*, &_block)
25
57
  end
26
58
  end
27
59
  end
@@ -30,7 +30,7 @@ module Usable
30
30
  end
31
31
  end
32
32
 
33
- # @description Directly include a module whose methods you want made available in +usable_config.available_methods+
33
+ # @description Directly include a module whose methods you want made available in +usables.available_methods+
34
34
  # Gives the module a name when including so that it shows up properly in the list of ancestors
35
35
  def use!(target)
36
36
  override
@@ -39,14 +39,14 @@ module Usable
39
39
  target.send :remove_const, const_name if target.const_defined? const_name, false
40
40
  target.const_set const_name, copy
41
41
  end
42
- target.usable_config.modules << copy
42
+ target.usables.add_module copy
43
43
  target.send options[:method], copy
44
44
  end
45
45
 
46
46
  # @description Includes or prepends the original module onto the target
47
47
  def use_original!(target)
48
48
  return unless has_spec?
49
- target.usable_config.modules << mod
49
+ target.usables.add_module mod
50
50
  target.send options[:method], mod
51
51
  end
52
52
 
@@ -1,3 +1,3 @@
1
1
  module Usable
2
- VERSION = "1.4.0".freeze
2
+ VERSION = "2.0.0".freeze
3
3
  end
data/lib/usable.rb CHANGED
@@ -5,10 +5,35 @@ require 'usable/mod_extender'
5
5
  require 'usable/config'
6
6
 
7
7
  module Usable
8
- def usable_config
9
- @usable_config ||= Config.new
8
+
9
+ # @description Define an instance level version of +usables+
10
+ def self.extended(base)
11
+ base.class_eval do
12
+ def usables
13
+ self.class.usables
14
+ end
15
+
16
+ def usable_method(method_name)
17
+ self.class.usable_method(self, method_name)
18
+ end
19
+ end
20
+ unless base.is_a? Class
21
+ base.instance_eval do
22
+ def config(&block)
23
+ usables(&block)
24
+ end unless defined? config
25
+ end
26
+ end
10
27
  end
11
- attr_writer :usable_config
28
+
29
+ # @description Read and write configuration options
30
+ def usables
31
+ @usables ||= Config.new
32
+ return @usables unless block_given?
33
+ @usables.instance_eval &Proc.new
34
+ end
35
+
36
+ attr_writer :usables
12
37
 
13
38
  # @description Configures the +available_methods+ of a module using the given options or block and then includes it on
14
39
  # the target class. Checks if there is a module named UsableSpec within the given mods namespace and uses the instance
@@ -18,8 +43,8 @@ module Usable
18
43
  #
19
44
  # class Example
20
45
  # extend Usable
21
- # usable Mixin, only: [:foo, :bar] do |config|
22
- # config.baz = "Available as `Example.usable_config.baz`"
46
+ # usable Mixin, only: [:foo, :bar] do
47
+ # baz "Available as `Example.usables.baz` or `Example.usables.mixin.baz`"
23
48
  # end
24
49
  # end
25
50
  #
@@ -32,13 +57,22 @@ module Usable
32
57
  # @option [Array,Symbol] :only Limit which methods are copied from the module
33
58
  # @option [String,Symbol] :method (:include) The method to use for including the module
34
59
  # @return [ModExtender] containing the original and modified module
35
- def usable(mod, options = {})
60
+ def usable(mod, options = {}, &block)
36
61
  usable_options = { only: options.delete(:only), method: options.delete(:method) }
37
- if mod.respond_to? :usable_config
38
- mod.usable_config.to_h.each { |k, v| usable_config.public_send "#{k}=", v }
62
+ # Define settings on @usables and on the scoped @usables
63
+ scope = Config.new
64
+ if mod.name
65
+ scope_name = mod.name.split('::').last.gsub(/\B([A-Z])([a-z_0-9])/, '_\1\2').downcase
66
+ usables[scope_name] = scope
67
+ end
68
+ if mod.respond_to? :usables
69
+ mod.usables.each do |k, v|
70
+ [scope, usables].each { |x| x.spec k, v }
71
+ end
39
72
  end
40
- options.each { |k, v| usable_config.public_send "#{k}=", v }
41
- yield usable_config if block_given?
73
+ [scope, usables].each { |x| options.each { |k, v| x[k] = v } }
74
+ [scope, usables].each { |x| x.instance_eval &block } if block_given?
75
+ # Include module
42
76
  mod_ext = ModExtender.new mod, usable_options
43
77
  mod_ext.use! self
44
78
  mod_ext.use_original! self
@@ -48,6 +82,6 @@ module Usable
48
82
 
49
83
  # @return [Method] bound to the given -context-
50
84
  def usable_method(context, method_name)
51
- usable_config.available_methods[method_name].bind(context)
85
+ usables.available_methods[method_name].bind(context)
52
86
  end
53
87
  end
data/usable.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["arebuckley@gmail.com"]
11
11
 
12
12
  spec.summary = %q{Mounts and configures modules}
13
- spec.description = %q{An elegant way to mount and configure your modules. Usable gives you control over which methods are included.}
13
+ spec.description = %q{Usable provides an elegant way to mount and configure your modules}
14
14
  spec.homepage = "https://github.com/ridiculous/usable"
15
15
  spec.license = "MIT"
16
16
 
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.4.0
4
+ version: 2.0.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-04-08 00:00:00.000000000 Z
11
+ date: 2016-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,8 +58,7 @@ dependencies:
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '4'
61
- description: An elegant way to mount and configure your modules. Usable gives you
62
- control over which methods are included.
61
+ description: Usable provides an elegant way to mount and configure your modules
63
62
  email:
64
63
  - arebuckley@gmail.com
65
64
  executables: []