usable 3.3.0 → 3.4.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: 37d7979f36f818a019b5e938f9271a09021d8740
4
- data.tar.gz: 52f7607ba637d7e1e50c2423797c0680c390af47
3
+ metadata.gz: eb11e2617182a394ba2fcf207926152e7cb93606
4
+ data.tar.gz: 2d7c5698ddd7a8984a791c29cad205f65a0ab6ab
5
5
  SHA512:
6
- metadata.gz: be661c7880726a1fd3235c88c6ac27218f5ed88dad72088ee72da40493ba54208e71743c8951c424095936249a09c2c8db329f262e781be683088d6a4fa0d7bf
7
- data.tar.gz: d074eea1d75951eaf494de6680a94d2cea4f721324570ef50a39c147276fedf85adac77ca5c464cc9d46a1e99a6a6a4d6281e992573196b8f2536affcdde4f6d
6
+ metadata.gz: 7d0835d8eff617914a7968af009e307804f638191f7025dc06a54bd8b89cdf205ea2c13a14ac92de4471f96e91ebfc1d8990d08df5ea78f5d33a42d1c7f05546
7
+ data.tar.gz: 485649445fcbc569624de03000756b61fe972686432d14c6b67db88b3f8988afc1db0109f1e6750f56b7f6c5f68b4aafeb23873b45218dc78cbf181f4aaa905b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ 3.4.0 (12/22/2016)
2
+ ==================
3
+
4
+ * FIX - Copying usable attributes from a module to class/module works as expected
5
+ * NEW - Pass `only: :constants` when mounting a module to import just the constants from a module
6
+
1
7
  3.3.0 (12/4/2016)
2
8
  =================
3
9
 
data/README.md CHANGED
@@ -3,7 +3,17 @@
3
3
  Usable provides an elegant way to mount and configure your modules. Class level settings can be configured on a per module basis,
4
4
  available to both the module and including class. Allows you to include only the methods you want.
5
5
 
6
- Configure a module to be usable
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'usable'
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ Configure a module to have "usable" defaults:
7
17
  ```ruby
8
18
  module VersionMixin
9
19
  extend Usable
@@ -24,7 +34,7 @@ module VersionMixin
24
34
  end
25
35
  ```
26
36
 
27
- Include the module into a class using `usable`, which will copy over any configuration options
37
+ Include the module into a class using `usable`, which will copy over the configs:
28
38
  ```ruby
29
39
  class Model
30
40
  extend Usable
@@ -118,15 +128,32 @@ So Usable gives the modified module a name, which is the same name as the origin
118
128
  Mixin => MixinUsed
119
129
  ```
120
130
 
121
- ## Installation
131
+ ## Tips and Tricks
122
132
 
123
- Add this line to your application's Gemfile:
133
+ #### __3.4__ _-(unreleased)_
134
+
135
+ Import just a module's constants:
124
136
 
125
137
  ```ruby
126
- gem 'usable'
138
+ usable ExampleMod, only: :constants
127
139
  ```
128
140
 
129
- ## Tips and Tricks
141
+ Currently works with `usable ExampleMod, only: []` since version 2.0
142
+
143
+ #### __since version 3.3__ _- (not required)_
144
+ The `Usable::Struct` function is available for creating value objects with defaults. If you `require "usable/struct"` the
145
+ class function is available to create classes:
146
+
147
+ ```ruby
148
+ class Route < Usable::Struct(paths: %w[api v2 v3])
149
+ end
150
+
151
+ Route.usables.to_h # => {:paths=>["api", "v2", "v3"]}
152
+ Route.new.paths # => ["api", "v2", "v3"]
153
+ Route.new(paths: nil).paths # => nil
154
+ ```
155
+
156
+ #### __since version 2.0__
130
157
 
131
158
  When usable modules define the same config setting, the last one mounted takes precedence. Fortunately,
132
159
  Usable also "stacks" config settings by namespacing them:
@@ -156,12 +183,6 @@ User.usables.human.speak # => "Hello"
156
183
  User.usables.robot.speak # => "beep bop"
157
184
  ```
158
185
 
159
- Import just a module's constants with this little trick:
160
-
161
- ```ruby
162
- usable ExampleMod, only: []
163
- ```
164
-
165
186
  ## Development
166
187
 
167
188
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/console CHANGED
@@ -3,6 +3,7 @@
3
3
  require "bundler/setup"
4
4
  require "usable"
5
5
  require "usable/struct"
6
+ require "byebug"
6
7
  require "irb"
7
8
 
8
9
  # You can add fixtures and/or initialization code here to make experimenting
@@ -78,4 +79,21 @@ end
78
79
 
79
80
  Model.usable PersistenceOverride, method: 'prepend'
80
81
 
82
+ def run_tests(subject)
83
+ if subject.usables.instance_variable_get(:@lazy_loads).to_a != [:model]
84
+ puts "Test @lazy_loads FAILED! Expected: #{[:model]}, Actual: #{subject.usables.instance_variable_get(:@lazy_loads)}"
85
+ end
86
+ if subject.usables.model != Model
87
+ puts "Test #model FAILED! Expected: #{Model}, Actual: #{subject.usables.model}"
88
+ end
89
+ if subject.usables.max_versions != 10
90
+ puts "Test #max_version FAILED! Expected: #{10}, Actual: #{subject.usables.max_versions}"
91
+ end
92
+ if subject.usables.model.new.save != 'nope'
93
+ puts "Test #save FAILED! Expected: 'nope', Actual: #{subject.usables.model.new.save}"
94
+ end
95
+ end
96
+
97
+ run_tests Example
98
+
81
99
  IRB.start
data/lib/usable/config.rb CHANGED
@@ -8,6 +8,7 @@ module Usable
8
8
  include ConfigRegister
9
9
  include ConfigMulti
10
10
 
11
+ # @todo Maybe keep a list of all attributes (lazy and regular)?
11
12
  def initialize(attributes = {})
12
13
  @spec = OpenStruct.new(attributes)
13
14
  @lazy_loads = Set.new
@@ -42,17 +43,23 @@ module Usable
42
43
  end
43
44
 
44
45
  def method_missing(key, *args, &block)
46
+ # @attributes << key.to_s
45
47
  if block
46
48
  @lazy_loads << key
47
- # @attributes << key.to_s
48
49
  @spec.define_singleton_method(key) { yield }
49
50
  else
50
- key = key.to_s.tr('=', '')
51
- # @attributes << key
51
+ # Needs to be a symbol so we can consistently access @lazy_loads
52
+ key = key.to_s.tr('=', '').to_sym
52
53
  if args.empty?
53
- value = @spec[key] ||= call_spec_method(key)
54
+ if @spec[key]
55
+ # Cleanup, just in case we loaded it another way (e.g. combining with another usable config)
56
+ @lazy_loads.delete key
57
+ else
58
+ @spec[key] = call_spec_method(key)
59
+ end
60
+ # Define method so we don't hit method missing again
54
61
  define_singleton_method(key) { @spec[key] }
55
- value
62
+ @spec[key]
56
63
  else
57
64
  @spec[key] = args.first
58
65
  end
@@ -1,17 +1,19 @@
1
1
  module Usable
2
2
  module ConfigMulti
3
3
  # It's important to define all block specs we need to lazy load
4
- # Set block specs to nil values so it will fallback to calling the underlying singleton method defined by Config#method_missing
5
4
  def +(other)
6
5
  config = clone
7
6
  specs = other.spec.to_h
8
7
  specs.each { |key, val| config[key] = val }
9
- methods = other.spec.singleton_methods - specs.keys
8
+ methods = other.spec.singleton_methods
9
+ methods.map! { |name| name.to_s.tr('=', '').to_sym }
10
+ methods.uniq!
11
+ methods -= specs.keys
10
12
  methods.each do |name|
11
- config.spec[name] = nil
12
13
  config.spec.define_singleton_method(name) do
13
14
  other.spec.public_method(name).call
14
15
  end
16
+ config.instance_variable_get(:@lazy_loads) << name
15
17
  end
16
18
  config
17
19
  end
@@ -9,7 +9,7 @@ module Usable
9
9
  @options[:method] ||= :include
10
10
  @copy = mod
11
11
  @name = mod.name
12
- @unwanted = options[:only] ? @copy.instance_methods - Array(options[:only]) : []
12
+ @unwanted = find_unwanted_methods(options[:only])
13
13
  if @unwanted.any?
14
14
  @copy = @copy.dup
15
15
  end
@@ -37,5 +37,14 @@ module Usable
37
37
  "UsableMod#{Time.now.strftime('%s')}"
38
38
  end
39
39
  end
40
+
41
+ def find_unwanted_methods(only)
42
+ return [] unless only
43
+ if :constants == only
44
+ @copy.instance_methods
45
+ else
46
+ @copy.instance_methods - Array(only)
47
+ end
48
+ end
40
49
  end
41
50
  end
@@ -1,3 +1,3 @@
1
1
  module Usable
2
- VERSION = "3.3.0".freeze
2
+ VERSION = "3.4.0".freeze
3
3
  end
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: 3.3.0
4
+ version: 3.4.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-12-05 00:00:00.000000000 Z
11
+ date: 2016-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler