ns-options 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2011-Present Collin Redding, Kelly Redding and Team Insight
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -89,6 +89,28 @@ App.settings.server # => NoMethodError
89
89
  App.settings.data.server # => 127.0.0.1:1234
90
90
  ```
91
91
 
92
+ ### Less Verbose Definitions
93
+
94
+ As an alternative to the above definition syntax, you can use an alternate less-verbose syntax:
95
+ * `opts` for `options`
96
+ * `opt` for `option`
97
+ * `ns` for `namespace`
98
+
99
+ ```ruby
100
+ module App
101
+ include NsOptions
102
+
103
+ opts :settings do
104
+ opt :root, Pathname
105
+ opt :stage
106
+
107
+ ns :other_stuff do
108
+ opt :something
109
+ end
110
+ end
111
+ end
112
+ ```
113
+
92
114
  #### With Classes
93
115
 
94
116
  Using `NsOptions` on a `Class` uses namespaces to create separate sets of options for every instance of your class created. This allows every instance to have different values for the set of options and not interfere with each other. For example with the following:
@@ -287,7 +309,44 @@ class Root < Pathname
287
309
  end
288
310
  ```
289
311
 
290
- With the revised `initialize` method, `NsOptions` will have no problems coercing values for your the type class. In some cases the above solution may not work for you, but don't worry. See the _Option Rules_ section for another way to solve this, specifically about the args rule. For an example of a custom type class, the included `NsOptions::Boolean` can be looked at. This is a special case, but it works as a type class with `NsOptions`.
312
+ With the revised `initialize` method, `NsOptions` will have no problems coercing values for the type class. In some cases the above solution may not work for you, but don't worry. See the _Option Rules_ section for another way to solve this, specifically about the args rule. For an example of a custom type class, the included `NsOptions::Boolean` can be looked at. This is a special case, but it works as a type class with `NsOptions`.
313
+
314
+ ### Custom type class return values
315
+
316
+ It may be useful to use a custom type class as a silent value handler. You don't necessarily care that this option is some handler class - you just want flexible ways to set its value and get a meaningful return value when you read it.
317
+
318
+ When reading option values, NsOptions will first check and see if the option value responds to the `returned_value` method. If it does, NsOptions will return that value instead of the instance of the type class. If not it will return the type class instance as normal.
319
+
320
+ The included `NsOptions::Boolean` handler class does just this to ensure it always returns either `true` or `false`. Here is another example:
321
+
322
+ ```ruby
323
+ class HostedAt
324
+ # sanitized :hosted_at config
325
+ # remove any trailing '/'
326
+ # ensure single leading '/'
327
+
328
+ def initialize(value)
329
+ @hosted_at = value.sub(/\/+$/, '').sub(/^\/*/, '/')
330
+ end
331
+
332
+ def returned_value
333
+ @hosted_at
334
+ end
335
+ end
336
+
337
+ class Thing
338
+ include NsOptions
339
+
340
+ options :is do
341
+ option :hosted_at, HostedAt
342
+ end
343
+ end
344
+
345
+ thing = Thing.new
346
+ thing.is.hosted_at # => nil
347
+ thing.is.hosted_at = "path/to/resource/"
348
+ thing.is.hosted_at # => "/path/to/resource"
349
+ ```
291
350
 
292
351
  ### Ruby Classes As A Type Class
293
352
 
@@ -314,7 +373,7 @@ Example.stuff.float = "5.0"
314
373
  Example.stuff.float # => 5.0, same as Float("5.0")
315
374
  ```
316
375
 
317
- `Symbol`, `Hash` and `Array` work, but ruby doesn't provide a built in type casting for these.
376
+ `Symbol`, `Hash` and `Array` work, but ruby doesn't provide built in type casting for these.
318
377
 
319
378
  ```ruby
320
379
  Example.stuff.symbol = "awesome"
@@ -358,6 +417,8 @@ App.settings.required_set? # => true
358
417
 
359
418
  To check if an option is set it will simply check if the value is not `nil`. If you are using a custom type class though, you can define an `is_set?` method and this will be used to check if an option is set.
360
419
 
420
+ The built in `required_set?` method checks to see if all the options for the namespace that have been marked `:required => true` are set. It does not recursively check any child namespaces.
421
+
361
422
  #### Args
362
423
 
363
424
  Another rule that you can specify is args. This allows you to pass more arguments to a type class.
@@ -387,7 +448,6 @@ Mix in NsOptions::Proxy to any module/class to make it proxy a namespace. This
387
448
 
388
449
  ```ruby
389
450
  module Something
390
- include NsOptions
391
451
  include NsOptions::Proxy
392
452
 
393
453
  # define options directly
@@ -431,27 +491,40 @@ module Something
431
491
  end
432
492
  ```
433
493
 
434
- ## License
494
+ ### Proxy initialization
435
495
 
436
- Copyright (c) 2011 Collin Redding and Team Insight
496
+ Mixing in Proxy with mixin a default initializer for you as well. This initializer allows you to call `new` on your proxy, passing it a hash of key-values. These key values will be applied to the proxy using the `Namespace#apply` logic. This allows you to use Proxy objects as option types and maintain the option type-casting and defaulting behavior.
437
497
 
438
- Permission is hereby granted, free of charge, to any person
439
- obtaining a copy of this software and associated documentation
440
- files (the "Software"), to deal in the Software without
441
- restriction, including without limitation the rights to use,
442
- copy, modify, merge, publish, distribute, sublicense, and/or sell
443
- copies of the Software, and to permit persons to whom the
444
- Software is furnished to do so, subject to the following
445
- conditions:
498
+ A Module example
446
499
 
447
- The above copyright notice and this permission notice shall be
448
- included in all copies or substantial portions of the Software.
500
+ ```ruby
501
+ module Things
502
+ include NsOptions::Proxy
449
503
 
450
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
451
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
452
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
453
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
454
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
455
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
456
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
457
- OTHER DEALINGS IN THE SOFTWARE.
504
+ option :one
505
+ option :two
506
+ end
507
+
508
+ # proxy defines a `new` method that takes a hash arg and
509
+ # applies it to the proxy
510
+ t = Thing.new(:one => 1, :two => 2, :three => 3)
511
+
512
+ # the values have been applied
513
+ t.to_hash # => {:one => 1, :two => 2, :three => 3}
514
+ ```
515
+
516
+ # A Class example
517
+
518
+ ```
519
+ class Thing
520
+ include NsOptions::Proxy
521
+
522
+ option :one
523
+ option :two
524
+ end
525
+
526
+ # proxy defines an `initialize` method that takes a hash arg and
527
+ # applies it to the proxy
528
+ t = Thing.new(:one => 1, :two => 2, :three => 3)
529
+ t.to_hash # => {:one => 1, :two => 2, :three => 3}
530
+ ```
@@ -11,6 +11,18 @@ module NsOptions
11
11
  @actual = self.convert(new_value)
12
12
  end
13
13
 
14
+ def ==(other_boolean)
15
+ if other_boolean.kind_of?(Boolean)
16
+ self.actual == other_boolean.actual
17
+ else
18
+ self.actual == other_boolean
19
+ end
20
+ end
21
+
22
+ def returned_value
23
+ self.actual
24
+ end
25
+
14
26
  protected
15
27
 
16
28
  def convert(value)
@@ -13,11 +13,13 @@ module NsOptions
13
13
 
14
14
  module DSL
15
15
 
16
- # This is the main DSL method for creating a namespace of options for your class/module. This
17
- # will define a class method for both classes and modules and an additional instance method
18
- # for classes. The namespace is then created and returned by calling the class method version.
19
- # For classes, the instance method will build an entirely new namespace from the class level
20
- # namespace. This is so when you define options at the class level:
16
+ # This is the main DSL method for creating a namespace of options for your
17
+ # class/module. This will define a class method for both classes and
18
+ # modules and an additional instance method for classes. The namespace is
19
+ # then created and returned by calling the class method version. For
20
+ # classes, the instance method will build an entirely new namespace from
21
+ # the class level namespace. This is so when you define options at the
22
+ # class level:
21
23
  #
22
24
  # class Something
23
25
  # include NsOptions
@@ -26,35 +28,23 @@ module NsOptions
26
28
  # end
27
29
  # end
28
30
  #
29
- # the namespaces at the instance level still get all the defined options, but are completely
30
- # separate objects from the class and other instances. Modules only deal with a single
31
- # namespace at the module level.
31
+ # the namespaces at the instance level still get all the defined options,
32
+ # but are completely separate objects from the class and other instances.
33
+ # Modules only deal with a single namespace at the module level.
34
+
35
+ # The options method takes three args:
36
+ # * `name` : what to name the defined methods for accessing the namespace
37
+ # * `key` : (optional) what to key the created namespace objects with
38
+ # - defaults to `name`
39
+ # - useful if persisting namespaces into some key-value store
40
+ # * `block`: (optional) a predefined set of nested options and namespaces
41
+
32
42
  def options(name, key = nil, &block)
33
43
  NsOptions::Helper.advisor.is_this_namespace_ok?(name, caller)
34
- key ||= name.to_s
35
- method_definitions = <<-CLASS_METHOD
36
-
37
- def self.#{name}(&block)
38
- @#{name} ||= NsOptions::Namespace.new('#{key}', &block)
39
- end
40
-
41
- CLASS_METHOD
42
- if self.kind_of?(Class)
43
- method_definitions += <<-INSTANCE_METHOD
44
-
45
- def #{name}(&block)
46
- unless @#{name}
47
- @#{name} = NsOptions::Namespace.new('#{key}', &block)
48
- @#{name}.options.build_from(self.class.#{name}.options, @#{name})
49
- end
50
- @#{name}
51
- end
52
-
53
- INSTANCE_METHOD
54
- end
55
- self.class_eval(method_definitions)
44
+ NsOptions::Helper.define_root_namespace_methods(self, name, key)
56
45
  self.send(name, &block)
57
46
  end
47
+ alias_method :opts, :options
58
48
 
59
49
  end
60
50
 
@@ -53,6 +53,35 @@ module NsOptions
53
53
  NsOptions::Helper::Advisor.new(namespace)
54
54
  end
55
55
 
56
+ def define_root_namespace_methods(define_on, name, key=nil)
57
+ key ||= name.to_s
58
+
59
+ # covers defining on Modules and at the class-level of Classes
60
+ method_definitions = <<-CLASS_METHOD
61
+
62
+ def self.#{name}(&block)
63
+ @#{name} ||= NsOptions::Namespace.new('#{key}', &block)
64
+ end
65
+
66
+ CLASS_METHOD
67
+
68
+ if define_on.kind_of?(Class)
69
+ # covers defining at the instance-level of Classes
70
+ method_definitions += <<-INSTANCE_METHOD
71
+
72
+ def #{name}(&block)
73
+ unless @#{name}
74
+ @#{name} = NsOptions::Namespace.new('#{key}', &block)
75
+ @#{name}.options.build_from(self.class.#{name}.options, @#{name})
76
+ end
77
+ @#{name}
78
+ end
79
+
80
+ INSTANCE_METHOD
81
+ end
82
+ define_on.class_eval(method_definitions)
83
+ end
84
+
56
85
  end
57
86
 
58
87
  end
@@ -37,6 +37,7 @@ module NsOptions
37
37
  NsOptions::Helper.define_option_methods(self, option)
38
38
  option
39
39
  end
40
+ alias_method :opt, :option
40
41
 
41
42
  # Define a namespace under this namespace. Firstly, a new key is constructured from this current
42
43
  # namespace's key and the name for the new namespace. The namespace is then added to the
@@ -60,6 +61,7 @@ module NsOptions
60
61
  NsOptions::Helper.define_namespace_methods(self, name)
61
62
  namespace
62
63
  end
64
+ alias_method :ns, :namespace
63
65
 
64
66
  # The opposite of #to_hash. Takes a hash representation of options and namespaces and mass
65
67
  # assigns option values.
@@ -26,7 +26,13 @@ module NsOptions
26
26
  # if reading a lazy_proc, call the proc and return its coerced return val
27
27
  # otherwise, just return the stored value
28
28
  def value
29
- self.lazy_proc?(@value) ? self.coerce(@value.call) : @value
29
+ if self.lazy_proc?(@value)
30
+ self.coerce(@value.call)
31
+ elsif @value.respond_to?(:returned_value)
32
+ @value.returned_value
33
+ else
34
+ @value
35
+ end
30
36
  end
31
37
 
32
38
  # if setting a lazy_proc, just store the proc off to be called when read
@@ -1,20 +1,38 @@
1
+ require 'ns-options'
2
+
1
3
  module NsOptions::Proxy
2
4
 
3
5
  # Mix this in to any module or class to make it proxy a namespace
4
6
  # this means you can interact with the module/class/class-instance as
5
- # if it were a namespace object itself. For example:
7
+ # if it were a namespace object itself.
6
8
 
7
9
  NAMESPACE = "__proxy_options__"
8
10
 
9
11
  class << self
10
12
 
11
13
  def included(receiver)
12
- receiver.class_eval do
13
- include NsOptions
14
- options(NAMESPACE)
14
+ NsOptions::Helper.define_root_namespace_methods(receiver, NAMESPACE)
15
+ receiver.class_eval { extend ProxyMethods }
16
+ receiver.class_eval { include ProxyMethods } if receiver.kind_of?(Class)
17
+
18
+ # default initializer method
19
+
20
+ if receiver.kind_of?(Class)
21
+ receiver.class_eval do
22
+
23
+ def initialize(configs={})
24
+ self.apply(configs || {})
25
+ end
26
+
27
+ end
28
+ else # Module
29
+ receiver.class_eval do
30
+
31
+ def self.new(configs={})
32
+ self.apply(configs || {})
33
+ end
15
34
 
16
- extend ProxyMethods
17
- include ProxyMethods
35
+ end
18
36
  end
19
37
  end
20
38
 
@@ -22,7 +40,44 @@ module NsOptions::Proxy
22
40
 
23
41
  module ProxyMethods
24
42
 
25
- # just proxy to the NAMESPACE created when Proxy was mixed in
43
+ # pass thru namespace methods to the proxied NAMESPACE handler
44
+
45
+ def option(*args, &block)
46
+ __proxy_options__.option(*args, &block)
47
+ end
48
+ alias_method :opt, :option
49
+
50
+ def namespace(*args, &block)
51
+ __proxy_options__.namespace(*args, &block)
52
+ end
53
+ alias_method :ns, :namespace
54
+
55
+ def apply(*args, &block)
56
+ __proxy_options__.apply(*args, &block)
57
+ end
58
+
59
+ def to_hash(*args, &block)
60
+ __proxy_options__.to_hash(*args, &block)
61
+ end
62
+
63
+ def each(*args, &block)
64
+ __proxy_options__.each(*args, &block)
65
+ end
66
+
67
+ def define(*args, &block)
68
+ __proxy_options__.define(*args, &block)
69
+ end
70
+
71
+ def required_set?(*args, &block)
72
+ __proxy_options__.required_set?(*args, &block)
73
+ end
74
+
75
+ def valid?(*args, &block)
76
+ __proxy_options__.valid?(*args, &block)
77
+ end
78
+
79
+ # for everything else, send to the proxied NAMESPACE handler
80
+ # at this point it really just enables setting dynamic options
26
81
 
27
82
  def method_missing(meth, *args, &block)
28
83
  if (po = self.__proxy_options__) && po.respond_to?(meth.to_s)
@@ -1,3 +1,3 @@
1
1
  module NsOptions
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -61,8 +61,7 @@ module App
61
61
  subject{ @module.settings.sub }
62
62
 
63
63
  should "have set the run_commands option" do
64
- assert_kind_of NsOptions::Boolean, subject.run_commands
65
- assert_equal @run, subject.run_commands.actual
64
+ assert_equal @run, subject.run_commands
66
65
  end
67
66
  end
68
67
 
@@ -0,0 +1,41 @@
1
+ require 'assert'
2
+
3
+ require 'ns-options/assert_macros'
4
+ require 'test/support/proxy'
5
+
6
+ class SomeProxyIntTests < Assert::Context
7
+ include NsOptions::AssertMacros
8
+
9
+ desc "the integration test proxy module"
10
+ setup do
11
+ @proxy = SomeProxy
12
+ end
13
+ subject { @proxy }
14
+
15
+ should have_option :some, SomeProxy::SomeThing, {
16
+ :default => {:value1 => 1}
17
+ }
18
+
19
+ should have_option :some_prime, SomeProxy::SomeThing, {
20
+ :default => {:value1 => 'one'}
21
+ }
22
+
23
+ should have_option :stuff, :default => []
24
+
25
+ end
26
+
27
+ class SomeProxySomeThingTests < SomeProxyIntTests
28
+ desc ":some option"
29
+ setup do
30
+ @proxy_some = @proxy.some
31
+ end
32
+ subject { @proxy_some }
33
+
34
+ should have_namespace :more
35
+ should have_options :value1, :value2
36
+
37
+ should "have its :value1 defaulted" do
38
+ assert_equal 1, subject.value1
39
+ end
40
+
41
+ end
@@ -79,8 +79,7 @@ class User
79
79
  end
80
80
 
81
81
  should "have set show_messages" do
82
- assert_kind_of NsOptions::Boolean, subject.show_messages
83
- assert_equal false, subject.show_messages.actual
82
+ assert_equal false, subject.show_messages
84
83
  end
85
84
 
86
85
  should "have set the font_size" do
@@ -0,0 +1,21 @@
1
+ module SomeProxy
2
+ include NsOptions::Proxy
3
+
4
+ class SomeThing
5
+ include NsOptions::Proxy
6
+
7
+ opt :value1
8
+ opt :value2
9
+
10
+ ns :more do
11
+ opt :other1
12
+ opt :other2
13
+ end
14
+
15
+ end
16
+
17
+ opt :some, SomeThing, :default => { :value1 => 1 }
18
+ opt :some_prime, SomeThing, :default => { :value1 => 'one' }
19
+ opt :stuff, :default => []
20
+
21
+ end
@@ -9,7 +9,17 @@ class NsOptions::Boolean
9
9
  end
10
10
  subject{ @boolean }
11
11
 
12
- should have_accessors :actual
12
+ should have_accessor :actual
13
+ should have_reader :returned_value
14
+
15
+ should "return its handled value with the `actual` method" do
16
+ assert_equal true, subject.actual
17
+ end
18
+
19
+ should "return its handled value with the `returned_value` method" do
20
+ assert_equal true, subject.returned_value
21
+ end
22
+
13
23
  end
14
24
 
15
25
  class WithTruthyValuesTest < BaseTest
@@ -80,4 +90,22 @@ class NsOptions::Boolean
80
90
  end
81
91
  end
82
92
 
93
+ class ComparatorTests < BaseTest
94
+ desc "when comparing for equality"
95
+ setup do
96
+ @true_bool = NsOptions::Boolean.new true
97
+ @false_bool = NsOptions::Boolean.new false
98
+ end
99
+
100
+ should "compare with other booleans" do
101
+ assert_equal NsOptions::Boolean.new(1), @true_bool
102
+ assert_equal NsOptions::Boolean.new(0), @false_bool
103
+ end
104
+
105
+ should "compare with true and false" do
106
+ assert_equal true, @true_bool
107
+ assert_equal false, @false_bool
108
+ end
109
+ end
110
+
83
111
  end
@@ -16,7 +16,7 @@ module NsOptions::HasOptions
16
16
  end
17
17
  subject{ @instance }
18
18
 
19
- should have_class_methods :options
19
+ should have_class_methods :options, :opts
20
20
 
21
21
  end
22
22
 
@@ -9,15 +9,19 @@ module NsOptions::Helper
9
9
  end
10
10
  subject{ @module }
11
11
 
12
- should have_instance_methods :find_and_define_namespace, :find_and_define_option,
13
- :define_namespace_methods, :define_option_methods, :advisor
14
-
12
+ should have_instance_method :find_and_define_namespace
13
+ should have_instance_method :find_and_define_option
14
+ should have_instance_method :define_namespace_methods
15
+ should have_instance_method :define_option_methods
16
+ should have_instance_method :advisor
17
+ should have_instance_method :define_root_namespace_methods
18
+
15
19
  should "return an instance of NsOptions::Helper::Advisor with a call to #advisor" do
16
20
  advisor = subject.advisor(NsOptions::Namespace.new("something"))
17
21
  assert_instance_of NsOptions::Helper::Advisor, advisor
18
22
  end
19
23
  end
20
-
24
+
21
25
  class FindAndDefineOptionTest < BaseTest
22
26
  desc "find_and_define_option method"
23
27
  setup do
@@ -26,14 +30,14 @@ module NsOptions::Helper
26
30
  @result = @module.find_and_define_option(@namespace, @option.name)
27
31
  end
28
32
  subject{ @namespace }
29
-
33
+
30
34
  should "have defined reader/writer methods for the option and returned the option" do
31
35
  assert_respond_to @option.name, subject
32
36
  assert_respond_to "#{@option.name}=", subject
33
37
  assert_equal @option, @result
34
38
  end
35
- end
36
-
39
+ end
40
+
37
41
  class FindAndDefineNamespaceTest < BaseTest
38
42
  desc "find_and_define_namespace method"
39
43
  setup do
@@ -42,7 +46,7 @@ module NsOptions::Helper
42
46
  @result = @module.find_and_define_namespace(@namespace, :else)
43
47
  end
44
48
  subject{ @namespace }
45
-
49
+
46
50
  should "have defined reader method for the namespace and returned the namespace" do
47
51
  assert_respond_to :else, subject
48
52
  assert_equal subject.options.get_namespace(:else), @result
@@ -11,7 +11,10 @@ class NsOptions::Namespace
11
11
  subject{ @namespace }
12
12
 
13
13
  should have_accessors :metaclass, :options
14
- should have_instance_methods :option, :namespace, :required_set?, :define, :apply, :valid?
14
+ should have_instance_methods :option, :opt
15
+ should have_instance_methods :namespace, :ns
16
+ should have_instance_methods :required_set?, :valid?
17
+ should have_instance_methods :define, :apply
15
18
  should have_instance_methods :to_hash, :each
16
19
 
17
20
  should "have set it's metaclass accessor" do
@@ -17,18 +17,23 @@ class NsOptions::Option
17
17
  should "have set the name" do
18
18
  assert_equal "stage", subject.name
19
19
  end
20
+
20
21
  should "have set the type class" do
21
22
  assert_equal String, subject.type_class
22
23
  end
24
+
23
25
  should "have set the rules" do
24
26
  assert_equal(@rules, subject.rules)
25
27
  end
28
+
26
29
  should "have defaulted value based on the rules" do
27
30
  assert_equal subject.rules[:default], subject.value
28
31
  end
32
+
29
33
  should "return true with a call to #required?" do
30
34
  assert_equal true, subject.required?
31
35
  end
36
+
32
37
  should "allow setting the value to nil" do
33
38
  subject.value = nil
34
39
  assert_nil subject.value
@@ -151,11 +156,13 @@ class NsOptions::Option
151
156
  subject.value = new_value
152
157
  assert_equal new_value, subject.value
153
158
  end
159
+
154
160
  should "allow setting it's value with a string and convert it" do
155
161
  new_value = "13.4"
156
162
  subject.value = new_value
157
163
  assert_equal new_value.to_f, subject.value
158
164
  end
165
+
159
166
  should "allow setting it's value with an integer and convert it" do
160
167
  new_value = 1
161
168
  subject.value = new_value
@@ -183,6 +190,7 @@ class NsOptions::Option
183
190
  subject.value = value
184
191
  assert_equal object_class.new.to_sym, subject.value
185
192
  end
193
+
186
194
  should "error on anything that doesn't define #to_sym" do
187
195
  assert_raises(NoMethodError) do
188
196
  subject.value = true
@@ -334,6 +342,68 @@ class NsOptions::Option
334
342
  end
335
343
  end
336
344
 
345
+ class WithReturnValueTests < BaseTest
346
+ setup do
347
+ # test control values
348
+ @string = NsOptions::Option.new(:string, String)
349
+ @symbol = NsOptions::Option.new(:symbol, Symbol)
350
+ @integer = NsOptions::Option.new(:integer, Integer)
351
+ @float = NsOptions::Option.new(:float, Float)
352
+ @hash = NsOptions::Option.new(:hash, Hash)
353
+ @array = NsOptions::Option.new(:array, Array)
354
+ @proc = NsOptions::Option.new(:proc, Proc)
355
+ @lazy_proc = NsOptions::Option.new(:lazy_proc)
356
+
357
+ # custom return value
358
+ class HostedAt
359
+ # sanitized :hosted_at config
360
+ # remove any trailing '/'
361
+ # ensure single leading '/'
362
+
363
+ def initialize(value)
364
+ @hosted_at = value.sub(/\/+$/, '').sub(/^\/*/, '/')
365
+ end
366
+
367
+ def returned_value
368
+ @hosted_at
369
+ end
370
+ end
371
+
372
+ @hosted_at = NsOptions::Option.new(:hosted_at, HostedAt)
373
+ end
374
+
375
+ should "return values normally when no `returned_value` is specified" do
376
+ @string.value = "test"
377
+ assert_equal "test", @string.value
378
+
379
+ @symbol.value = :test
380
+ assert_equal :test, @symbol.value
381
+
382
+ @integer.value = 1
383
+ assert_equal 1, @integer.value
384
+
385
+ @float.value = 1.1
386
+ assert_equal 1.1, @float.value
387
+
388
+ @hash.value = {:test => 'test'}
389
+ assert_equal({:test => 'test'}, @hash.value)
390
+
391
+ @array.value = ['test']
392
+ assert_equal ['test'], @array.value
393
+
394
+ @proc.value = Proc.new { 'test' }
395
+ assert_kind_of Proc, @proc.value
396
+
397
+ @lazy_proc.value = Proc.new { 'lazy test' }
398
+ assert_equal 'lazy test', @lazy_proc.value
399
+ end
400
+
401
+ should "should honor `returned_value` when returning option values" do
402
+ @hosted_at.value = "path/to/resource/"
403
+ assert_equal '/path/to/resource', @hosted_at.value
404
+ end
405
+ end
406
+
337
407
  class WithArgsTest < BaseTest
338
408
  desc "with args rule"
339
409
  setup do
@@ -8,15 +8,22 @@ module NsOptions::Proxy
8
8
  def self.proxy_a_namespace
9
9
  Assert::Macro.new do
10
10
  should "create a default namespace to proxy to" do
11
- assert_respond_to NAMESPACE, subject
12
- assert_kind_of NsOptions::Namespace, subject.send(NAMESPACE)
11
+ assert_respond_to '__proxy_options__', subject
12
+ assert_kind_of NsOptions::Namespace, subject.send('__proxy_options__')
13
13
  end
14
14
 
15
- should "respond to namespace methods" do
16
- assert_respond_to :option, subject
17
- assert_respond_to :namespace, subject
18
- assert_respond_to :to_hash, subject
19
- assert_respond_to :each, subject
15
+ should "respond to proxied namespace methods" do
16
+ assert_respond_to :option, subject
17
+ assert_respond_to :opt, subject
18
+ assert_respond_to :namespace, subject
19
+ assert_respond_to :ns, subject
20
+ assert_respond_to :apply, subject
21
+ assert_respond_to :to_hash, subject
22
+ assert_respond_to :each, subject
23
+ assert_respond_to :define, subject
24
+ assert_respond_to :inspect, subject
25
+ assert_respond_to :required_set?, subject
26
+ assert_respond_to :valid?, subject
20
27
  end
21
28
 
22
29
  should "create options directly" do
@@ -41,22 +48,45 @@ module NsOptions::Proxy
41
48
  desc "when mixed in to a module"
42
49
  setup do
43
50
  @mod = Module.new do
44
- include NsOptions
45
51
  include NsOptions::Proxy
52
+
53
+ option :test
46
54
  end
47
55
  end
48
56
  subject { @mod }
49
57
 
50
58
  should proxy_a_namespace
51
59
 
60
+ should "allow building from a hash of key-values" do
61
+ subject.new('test' => 1, 'more' => 2)
62
+
63
+ assert_equal 1, subject.test
64
+ assert_equal 2, subject.more
65
+ end
66
+
67
+ should "take `new` method overrides" do
68
+ @newmod = Module.new do
69
+ include NsOptions::Proxy
70
+
71
+ def self.new
72
+ # nothing
73
+ end
74
+ end
75
+
76
+ assert_raises ArgumentError do
77
+ @newmod.new('test' => 1, 'more' => 2)
78
+ end
79
+ end
80
+
52
81
  end
53
82
 
54
83
  class ClassTests < BaseTests
55
84
  desc "when mixed into a class"
56
85
  setup do
57
86
  @cls = Class.new do
58
- include NsOptions
59
87
  include NsOptions::Proxy
88
+
89
+ option :test
60
90
  end
61
91
  end
62
92
 
@@ -72,6 +102,27 @@ module NsOptions::Proxy
72
102
  subject { @cls.new }
73
103
  should proxy_a_namespace
74
104
 
105
+ should "allow building from a hash of key-values" do
106
+ thing = @cls.new(:test => 1, :more => 2)
107
+
108
+ assert_equal 1, thing.test
109
+ assert_equal 2, thing.more
110
+ end
111
+
112
+ should "take init method overrides" do
113
+ @newcls = Class.new do
114
+ include NsOptions::Proxy
115
+
116
+ def initialize
117
+ # nothing
118
+ end
119
+ end
120
+
121
+ assert_raises ArgumentError do
122
+ @newcls.new('test' => 1, 'more' => 2)
123
+ end
124
+ end
125
+
75
126
  end
76
127
 
77
128
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ns-options
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 1
10
- version: 0.3.1
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Collin Redding
@@ -15,10 +15,11 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-30 00:00:00 Z
18
+ date: 2012-05-21 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  type: :development
22
+ prerelease: false
22
23
  requirement: &id001 !ruby/object:Gem::Requirement
23
24
  none: false
24
25
  requirements:
@@ -29,11 +30,11 @@ dependencies:
29
30
  - 0
30
31
  - 7
31
32
  version: "0.7"
32
- prerelease: false
33
- name: assert
34
33
  version_requirements: *id001
34
+ name: assert
35
35
  - !ruby/object:Gem::Dependency
36
36
  type: :development
37
+ prerelease: false
37
38
  requirement: &id002 !ruby/object:Gem::Requirement
38
39
  none: false
39
40
  requirements:
@@ -44,9 +45,8 @@ dependencies:
44
45
  - 0
45
46
  - 1
46
47
  version: "0.1"
47
- prerelease: false
48
- name: assert-mocha
49
48
  version_requirements: *id002
49
+ name: assert-mocha
50
50
  description: Define and use namespaced options with a clean interface.
51
51
  email:
52
52
  - collin.redding@reelfx.com
@@ -59,7 +59,8 @@ extra_rdoc_files: []
59
59
  files:
60
60
  - .gitignore
61
61
  - Gemfile
62
- - README.markdown
62
+ - LICENSE
63
+ - README.md
63
64
  - Rakefile
64
65
  - lib/ns-options.rb
65
66
  - lib/ns-options/assert_macros.rb
@@ -78,9 +79,11 @@ files:
78
79
  - ns-options.gemspec
79
80
  - test/helper.rb
80
81
  - test/integration/app_test.rb
82
+ - test/integration/proxy_test.rb
81
83
  - test/integration/user_test.rb
82
84
  - test/irb.rb
83
85
  - test/support/app.rb
86
+ - test/support/proxy.rb
84
87
  - test/support/user.rb
85
88
  - test/unit/ns-options/assert_macros_test.rb
86
89
  - test/unit/ns-options/boolean_test.rb
@@ -128,9 +131,11 @@ summary: Define and use namespaced options with a clean interface.
128
131
  test_files:
129
132
  - test/helper.rb
130
133
  - test/integration/app_test.rb
134
+ - test/integration/proxy_test.rb
131
135
  - test/integration/user_test.rb
132
136
  - test/irb.rb
133
137
  - test/support/app.rb
138
+ - test/support/proxy.rb
134
139
  - test/support/user.rb
135
140
  - test/unit/ns-options/assert_macros_test.rb
136
141
  - test/unit/ns-options/boolean_test.rb