fusu 0.2.0 → 0.2.1

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
- SHA1:
3
- metadata.gz: 5b0df9b35cbcd397ff4eaa1702330e0e0255f84a
4
- data.tar.gz: 40b28b9e12efa5cf79f00171311c62e3616e0a37
2
+ SHA256:
3
+ metadata.gz: abe9860bb714eb06dff8a1df416ee4002883d1f74a66166eb9ca61331f10cf35
4
+ data.tar.gz: 0472026d1cc75b37592ad0d61618c4e7dc3c1bc2711a8a73c1761fa3f95ac213
5
5
  SHA512:
6
- metadata.gz: 028aaafaf603c46939c503d0f4b422fc4649503968d620b950e647f1b0ae4f33dce8d0dd5b7839e58d48bbc5cc6df1e79038c6b9d8478619a5ad5b4b81e34ad1
7
- data.tar.gz: 28e4994d51bcdb01fd825e0382f5e4c312006a649872443a5ccb31f8ba3a5ff2bf222d86d0e53f40bf846926a644d1b35cb2558cd8f074a24c6d3eb809cec4b2
6
+ metadata.gz: 4a6b3ff3d19907727179ec8fe2646b3e88eb1047f4e90423bad354766e07c464e4b909807f9d75b05c9ad1359e1af4f5ee1e62359ea2a5ed35560f9f8122e9e5
7
+ data.tar.gz: db21445a5c0d8d4aa3f351f9ba42bcde5d293fd9a37bddac66f350ace8678fac0ab0bd54de3e3763fc07e296e0ba77beebd898887db6037c6facaa55b9f076eb
@@ -10,3 +10,5 @@ require "fusu/hash"
10
10
  require "fusu/string"
11
11
  require "fusu/regexp"
12
12
  require "fusu/hash_with_indifferent_access"
13
+ require "fusu/configurable"
14
+ require "fusu/concern"
@@ -9,5 +9,22 @@ module Fusu
9
9
  [object]
10
10
  end
11
11
  end
12
+
13
+ # Extracts options from a set of arguments. Removes and returns the last
14
+ # element in the array if it's a hash, otherwise returns a blank hash.
15
+ #
16
+ # def options(*args)
17
+ # args.extract_options!
18
+ # end
19
+ #
20
+ # options(1, 2) # => {}
21
+ # options(1, 2, a: :b) # => {:a=>:b}
22
+ def self.extract_options!(ary)
23
+ if ary.last.is_a?(::Hash) && Fusu::Hash.extractable_options?(ary.last)
24
+ ary.pop
25
+ else
26
+ {}
27
+ end
28
+ end
12
29
  end
13
30
  end
@@ -11,5 +11,9 @@ module Fusu
11
11
  false
12
12
  end
13
13
  end
14
+
15
+ def presence(elem)
16
+ blank?(elem) ? nil : elem
17
+ end
14
18
  end
15
19
  end
@@ -0,0 +1,146 @@
1
+ require "fusu/concern"
2
+ require "fusu/ordered_options"
3
+
4
+ module Fusu
5
+ # Configurable provides a <tt>config</tt> method to store and retrieve
6
+ # configuration options as an <tt>OrderedHash</tt>.
7
+ module Configurable
8
+ extend Fusu::Concern
9
+
10
+ class Configuration < Fusu::InheritableOptions
11
+ def compile_methods!
12
+ self.class.compile_methods!(keys)
13
+ end
14
+
15
+ # Compiles reader methods so we don't have to go through method_missing.
16
+ def self.compile_methods!(keys)
17
+ keys.reject { |m| method_defined?(m) }.each do |key|
18
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
19
+ def #{key}; _get(#{key.inspect}); end
20
+ RUBY
21
+ end
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ def config
27
+ @_config ||= if respond_to?(:superclass) && superclass.respond_to?(:config)
28
+ superclass.config.inheritable_copy
29
+ else
30
+ # create a new "anonymous" class that will host the compiled reader methods
31
+ Class.new(Configuration).new
32
+ end
33
+ end
34
+
35
+ def configure
36
+ yield config
37
+ end
38
+
39
+ # Allows you to add shortcut so that you don't have to refer to attribute
40
+ # through config. Also look at the example for config to contrast.
41
+ #
42
+ # Defines both class and instance config accessors.
43
+ #
44
+ # class User
45
+ # include Fusu::Configurable
46
+ # config_accessor :allowed_access
47
+ # end
48
+ #
49
+ # User.allowed_access # => nil
50
+ # User.allowed_access = false
51
+ # User.allowed_access # => false
52
+ #
53
+ # user = User.new
54
+ # user.allowed_access # => false
55
+ # user.allowed_access = true
56
+ # user.allowed_access # => true
57
+ #
58
+ # User.allowed_access # => false
59
+ #
60
+ # The attribute name must be a valid method name in Ruby.
61
+ #
62
+ # class User
63
+ # include Fusu::Configurable
64
+ # config_accessor :"1_Badname"
65
+ # end
66
+ # # => NameError: invalid config attribute name
67
+ #
68
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
69
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ #
71
+ # class User
72
+ # include Fusu::Configurable
73
+ # config_accessor :allowed_access, instance_reader: false, instance_writer: false
74
+ # end
75
+ #
76
+ # User.allowed_access = false
77
+ # User.allowed_access # => false
78
+ #
79
+ # User.new.allowed_access = true # => NoMethodError
80
+ # User.new.allowed_access # => NoMethodError
81
+ #
82
+ # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
83
+ #
84
+ # class User
85
+ # include Fusu::Configurable
86
+ # config_accessor :allowed_access, instance_accessor: false
87
+ # end
88
+ #
89
+ # User.allowed_access = false
90
+ # User.allowed_access # => false
91
+ #
92
+ # User.new.allowed_access = true # => NoMethodError
93
+ # User.new.allowed_access # => NoMethodError
94
+ #
95
+ # Also you can pass a block to set up the attribute with a default value.
96
+ #
97
+ # class User
98
+ # include Fusu::Configurable
99
+ # config_accessor :hair_colors do
100
+ # [:brown, :black, :blonde, :red]
101
+ # end
102
+ # end
103
+ #
104
+ # User.hair_colors # => [:brown, :black, :blonde, :red]
105
+ def config_accessor(*names)
106
+ options = Fusu::Array.extract_options!(names)
107
+
108
+ names.each do |name|
109
+ raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
110
+
111
+ reader, reader_line = "def #{name}; config.#{name}; end", __LINE__
112
+ writer, writer_line = "def #{name}=(value); config.#{name} = value; end", __LINE__
113
+
114
+ singleton_class.class_eval reader, __FILE__, reader_line
115
+ singleton_class.class_eval writer, __FILE__, writer_line
116
+
117
+ unless options[:instance_accessor] == false
118
+ class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
119
+ class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
120
+ end
121
+ send("#{name}=", yield) if block_given?
122
+ end
123
+ end
124
+ private :config_accessor
125
+ end
126
+
127
+ # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
128
+ #
129
+ # require 'fusu/configurable'
130
+ #
131
+ # class User
132
+ # include Fusu::Configurable
133
+ # end
134
+ #
135
+ # user = User.new
136
+ #
137
+ # user.config.allowed_access = true
138
+ # user.config.level = 1
139
+ #
140
+ # user.config.allowed_access # => true
141
+ # user.config.level # => 1
142
+ def config
143
+ @_config ||= self.class.config.inheritable_copy
144
+ end
145
+ end
146
+ end
@@ -8,5 +8,13 @@ module Fusu
8
8
  extend Keys
9
9
  extend ReverseMerge
10
10
  extend DeepMerge
11
+
12
+ def extractable_options?(elem)
13
+ elem.instance_of?(::Hash)
14
+ end
15
+
16
+ def reject_key(hash, *keys)
17
+ hash.reject{ |k, v| keys.include?(k) }
18
+ end
11
19
  end
12
20
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fusu
4
+ # Usually key value pairs are handled something like this:
5
+ #
6
+ # h = {}
7
+ # h[:boy] = 'John'
8
+ # h[:girl] = 'Mary'
9
+ # h[:boy] # => 'John'
10
+ # h[:girl] # => 'Mary'
11
+ # h[:dog] # => nil
12
+ #
13
+ # Using +OrderedOptions+, the above code could be reduced to:
14
+ #
15
+ # h = ActiveSupport::OrderedOptions.new
16
+ # h.boy = 'John'
17
+ # h.girl = 'Mary'
18
+ # h.boy # => 'John'
19
+ # h.girl # => 'Mary'
20
+ # h.dog # => nil
21
+ #
22
+ # To raise an exception when the value is blank, append a
23
+ # bang to the key name, like:
24
+ #
25
+ # h.dog! # => raises KeyError: :dog is blank
26
+ #
27
+ class OrderedOptions < ::Hash
28
+ alias_method :_get, :[] # preserve the original #[] method
29
+ protected :_get # make it protected
30
+
31
+ def []=(key, value)
32
+ super(key.to_sym, value)
33
+ end
34
+
35
+ def [](key)
36
+ super(key.to_sym)
37
+ end
38
+
39
+ def method_missing(name, *args)
40
+ name_string = name.to_s
41
+ if name_string.chomp!("=")
42
+ self[name_string] = args.first
43
+ else
44
+ bangs = name_string.chomp!("!")
45
+
46
+ if bangs
47
+ Fusu.presence(self[name_string]) || raise(KeyError.new(":#{name_string} is blank"))
48
+ else
49
+ self[name_string]
50
+ end
51
+ end
52
+ end
53
+
54
+ def respond_to_missing?(name, include_private)
55
+ true
56
+ end
57
+ end
58
+
59
+ # +InheritableOptions+ provides a constructor to build an +OrderedOptions+
60
+ # hash inherited from another hash.
61
+ #
62
+ # Use this if you already have some hash and you want to create a new one based on it.
63
+ #
64
+ # h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
65
+ # h.girl # => 'Mary'
66
+ # h.boy # => 'John'
67
+ class InheritableOptions < OrderedOptions
68
+ def initialize(parent = nil)
69
+ if parent.kind_of?(OrderedOptions)
70
+ # use the faster _get when dealing with OrderedOptions
71
+ super() { |h, k| parent._get(k) }
72
+ elsif parent
73
+ super() { |h, k| parent[k] }
74
+ else
75
+ super()
76
+ end
77
+ end
78
+
79
+ def inheritable_copy
80
+ self.class.new(self)
81
+ end
82
+ end
83
+ end
@@ -1,3 +1,3 @@
1
1
  module Fusu
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fusu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artur Panyach
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-02 00:00:00.000000000 Z
11
+ date: 2018-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,12 +74,14 @@ files:
74
74
  - lib/fusu/array.rb
75
75
  - lib/fusu/blank.rb
76
76
  - lib/fusu/concern.rb
77
+ - lib/fusu/configurable.rb
77
78
  - lib/fusu/hash.rb
78
79
  - lib/fusu/hash/deep_merge.rb
79
80
  - lib/fusu/hash/except.rb
80
81
  - lib/fusu/hash/keys.rb
81
82
  - lib/fusu/hash/reverse_merge.rb
82
83
  - lib/fusu/hash_with_indifferent_access.rb
84
+ - lib/fusu/ordered_options.rb
83
85
  - lib/fusu/regexp.rb
84
86
  - lib/fusu/string.rb
85
87
  - lib/fusu/string/methods.rb
@@ -105,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
107
  version: '0'
106
108
  requirements: []
107
109
  rubyforge_project:
108
- rubygems_version: 2.2.3
110
+ rubygems_version: 2.7.6
109
111
  signing_key:
110
112
  specification_version: 4
111
113
  summary: Functional support