fusu 0.2.0 → 0.2.1
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 +5 -5
- data/lib/fusu.rb +2 -0
- data/lib/fusu/array.rb +17 -0
- data/lib/fusu/blank.rb +4 -0
- data/lib/fusu/configurable.rb +146 -0
- data/lib/fusu/hash.rb +8 -0
- data/lib/fusu/ordered_options.rb +83 -0
- data/lib/fusu/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: abe9860bb714eb06dff8a1df416ee4002883d1f74a66166eb9ca61331f10cf35
|
4
|
+
data.tar.gz: 0472026d1cc75b37592ad0d61618c4e7dc3c1bc2711a8a73c1761fa3f95ac213
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a6b3ff3d19907727179ec8fe2646b3e88eb1047f4e90423bad354766e07c464e4b909807f9d75b05c9ad1359e1af4f5ee1e62359ea2a5ed35560f9f8122e9e5
|
7
|
+
data.tar.gz: db21445a5c0d8d4aa3f351f9ba42bcde5d293fd9a37bddac66f350ace8678fac0ab0bd54de3e3763fc07e296e0ba77beebd898887db6037c6facaa55b9f076eb
|
data/lib/fusu.rb
CHANGED
data/lib/fusu/array.rb
CHANGED
@@ -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
|
data/lib/fusu/blank.rb
CHANGED
@@ -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
|
data/lib/fusu/hash.rb
CHANGED
@@ -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
|
data/lib/fusu/version.rb
CHANGED
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.
|
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:
|
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.
|
110
|
+
rubygems_version: 2.7.6
|
109
111
|
signing_key:
|
110
112
|
specification_version: 4
|
111
113
|
summary: Functional support
|