usable 1.4.0 → 2.0.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: 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: []