lotus-utils 0.0.0 → 0.1.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: 635f90690f0d715100766bedfc746f1ee9a977e9
4
- data.tar.gz: 6517b4075a02732076484155950e8f177269ba88
3
+ metadata.gz: ab1fa641a480652c1773fc1808f2f920e10e0ffa
4
+ data.tar.gz: 6c59b62ec336ef0a4e13c64a0e8f71f45dded958
5
5
  SHA512:
6
- metadata.gz: d4b96ccd1aaffb8a3cddad8a96cf56b9b3ef899b1779b35fc09c3dee302e1f25539ab912eeeaf0cc3b5d8e60f8c2d347bfab07b52eafe1d610d80a8e019e8049
7
- data.tar.gz: 829dfd916801ed046c0bf08071dacbdfd9a6dc61e08f7baf00232d27ec07270795dfd2ed9117ab227fc4778b8d7a2997b93c322ad7881e883d88452fca78a3db
6
+ metadata.gz: 7dd6940ce3dbebec5d04ae5f05ecb67e2c41cca40579d09d637f0c5a1c64cad083408bff258ec815cfce93480b17d871662e23bc85ae7b7b88a986e115a36978
7
+ data.tar.gz: 17686034d0c2003a2e42dc1d386b5cd22dc55ebb45cce29707e4283c47a05036b0aefb13e3ad00a34a43547e0efb9dca2f8369ad716b65d24838efd3e6cbe42d
data/.coveralls.yml ADDED
@@ -0,0 +1,2 @@
1
+ service_name: travis-pro
2
+ repo_token: xXwDghSC1DjiaetDmdYbITJam1xJOGIRZ
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ .greenbar
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ script: 'bundle exec rake'
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.0
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ LICENSE.txt
3
+ lib/**/*.rb
data/Gemfile CHANGED
@@ -1,4 +1,10 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in lotus-utils.gemspec
4
2
  gemspec
3
+
4
+ unless ENV['TRAVIS']
5
+ gem 'debugger', require: false, platforms: :ruby
6
+ gem 'yard', require: false
7
+ gem 'simplecov', require: false
8
+ end
9
+
10
+ gem 'coveralls', require: false
data/README.md CHANGED
@@ -1,6 +1,26 @@
1
1
  # Lotus::Utils
2
2
 
3
- TODO: Write a gem description
3
+ Ruby core extentions and class utilities for [Lotus](http://lotusrb.org)
4
+
5
+ ## Status
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/lotus-utils.png)](http://badge.fury.io/rb/lotus-utils)
8
+ [![Build Status](https://secure.travis-ci.org/lotus/utils.png?branch=master)](http://travis-ci.org/lotus/utils?branch=master)
9
+ [![Test Coverage](https://coveralls.io/repos/lotus/utils/badge.png?branch=master)](https://coveralls.io/r/lotus/utils)
10
+ [![Code quality](https://codeclimate.com/github/lotus/utils.png)](https://codeclimate.com/github/lotus/utils)
11
+ [![Dependencies](https://gemnasium.com/lotus/utils.png)](https://gemnasium.com/lotus/utils)
12
+
13
+ ## Contact
14
+
15
+ * Home page: http://lotusrb.org
16
+ * Mailing List: http://lotusrb.org/mailing-list
17
+ * API Doc: http://rdoc.info/gems/lotus-utils
18
+ * Bugs/Issues: https://github.com/lotus/utils/issues
19
+ * Support: http://stackoverflow.com/questions/tagged/lotusrb
20
+
21
+ ## Rubies
22
+
23
+ __Lotus::Utils__ supports Ruby (MRI) 2+
4
24
 
5
25
  ## Installation
6
26
 
@@ -18,12 +38,24 @@ Or install it yourself as:
18
38
 
19
39
  ## Usage
20
40
 
21
- TODO: Write usage instructions here
41
+ __Lotus::Utils__ is designed to enhance Ruby's code and stdlib.
42
+ By default this gem doesn't load any code, require yourself what you need.
43
+
44
+ Please read the documentation of each module, in order to understand how to use
45
+ each feature.
46
+
47
+ ## Versioning
48
+
49
+ __Lotus::Utils__ uses [Semantic Versioning 2.0.0](http://semver.org)
22
50
 
23
51
  ## Contributing
24
52
 
25
- 1. Fork it ( http://github.com/<my-github-username>/lotus-utils/fork )
53
+ 1. Fork it
26
54
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
55
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
56
  4. Push to the branch (`git push origin my-new-feature`)
29
57
  5. Create new Pull Request
58
+
59
+ ## Copyright
60
+
61
+ Copyright 2014 Luca Guidi – Released under MIT License
data/Rakefile CHANGED
@@ -1 +1,10 @@
1
- require "bundler/gem_tasks"
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'bundler/gem_tasks'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = 'test/**/*_test.rb'
7
+ t.libs.push 'test'
8
+ end
9
+
10
+ task default: :test
@@ -0,0 +1,207 @@
1
+ module Lotus
2
+ module Utils
3
+ # Before and After callbacks
4
+ #
5
+ # @since 0.1.0
6
+ # @private
7
+ module Callbacks
8
+ # Series of callbacks to be executed
9
+ #
10
+ # @since 0.1.0
11
+ # @private
12
+ class Chain < ::Array
13
+ # Adds the given callbacks to the chain
14
+ #
15
+ # @param callbacks [Array] one or multiple callbacks to add
16
+ # @param blk [Proc] an optional block to be added
17
+ #
18
+ # @return [void]
19
+ #
20
+ # @see #run
21
+ # @see Lotus::Utils::Callbacks::Callback
22
+ # @see Lotus::Utils::Callbacks::MethodCallback
23
+ #
24
+ # @since 0.1.0
25
+ #
26
+ # @example
27
+ # require 'lotus/utils/callbacks'
28
+ #
29
+ # chain = Lotus::Utils::Callbacks::Chain.new
30
+ #
31
+ # # Add a Proc to be used as a callback, it will be wrapped by `Callback`
32
+ # # The optional argument(s) correspond to the one passed when invoked the chain with `run`.
33
+ # chain.add { Authenticator.authenticate! }
34
+ # chain.add {|params| ArticleRepository.find(params[:id]) }
35
+ #
36
+ # # Add a Symbol as a reference to a method name that will be used as a callback.
37
+ # # It will wrapped by `MethodCallback`
38
+ # # If the #notificate method accepts some argument(s) they should be passed when `run` is invoked.
39
+ # chain.add :notificate
40
+ def add(*callbacks, &blk)
41
+ callbacks.push blk if block_given?
42
+ callbacks.each do |c|
43
+ push Factory.fabricate(c)
44
+ end
45
+
46
+ uniq!
47
+ end
48
+
49
+ # Runs all the callbacks in the chain.
50
+ # The only two ways to stop the execution are: `raise` or `throw`.
51
+ #
52
+ # @param context [Object] the context where we want the chain to be invoked.
53
+ # @param args [Array] the arguments that we want to pass to each single callback.
54
+ #
55
+ # @since 0.1.0
56
+ #
57
+ # @example
58
+ # require 'lotus/utils/callbacks'
59
+ #
60
+ # class Action
61
+ # private
62
+ # def authenticate!
63
+ # end
64
+ #
65
+ # def set_article(params)
66
+ # end
67
+ # end
68
+ #
69
+ # action = Action.new
70
+ # params = Hash[id: 23]
71
+ #
72
+ # chain = Lotus::Utils::Callbacks::Chain.new
73
+ # chain.add :authenticate!, :set_article
74
+ #
75
+ # chain.run(action, params)
76
+ #
77
+ # # `params` will only be passed as #set_article argument, because it has an arity greater than zero
78
+ #
79
+ #
80
+ #
81
+ # chain = Lotus::Utils::Callbacks::Chain.new
82
+ #
83
+ # chain.add do
84
+ # # some authentication logic
85
+ # end
86
+ #
87
+ # chain.add do |params|
88
+ # # some other logic that requires `params`
89
+ # end
90
+ #
91
+ # chain.run(action, params)
92
+ #
93
+ # Those callbacks will be invoked within the context of `action`.
94
+ def run(context, *args)
95
+ each do |callback|
96
+ callback.call(context, *args)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Callback factory
102
+ #
103
+ # @since 0.1.0
104
+ # @private
105
+ class Factory
106
+ # Instantiates a `Callback` according to if it responds to #call.
107
+ #
108
+ # @param callback [Object] the object that needs to be wrapped
109
+ #
110
+ # @return [Callback, MethodCallback]
111
+ #
112
+ # @since 0.1.0
113
+ #
114
+ # @example
115
+ # require 'lotus/utils/callbacks'
116
+ #
117
+ # callable = Proc.new{} # it responds to #call
118
+ # method = :upcase # it doesn't responds to #call
119
+ #
120
+ # Lotus::Utils::Callbacks::Factory.fabricate(callable).class
121
+ # # => Lotus::Utils::Callbacks::Callback
122
+ #
123
+ # Lotus::Utils::Callbacks::Factory.fabricate(method).class
124
+ # # => Lotus::Utils::Callbacks::MethodCallback
125
+ def self.fabricate(callback)
126
+ if callback.respond_to?(:call)
127
+ Callback.new(callback)
128
+ else
129
+ MethodCallback.new(callback)
130
+ end
131
+ end
132
+ end
133
+
134
+ # Proc callback
135
+ # It wraps an object that responds to #call
136
+ #
137
+ # @since 0.1.0
138
+ # @private
139
+ class Callback
140
+ attr_reader :callback
141
+
142
+ # Initialize by wrapping the given callback
143
+ #
144
+ # @param callback [Object] the original callback that needs to be wrapped
145
+ #
146
+ # @return [Callback] self
147
+ #
148
+ # @since 0.1.0
149
+ #
150
+ def initialize(callback)
151
+ @callback = callback
152
+ end
153
+
154
+ # Executes the callback within the given context and passing the given arguments.
155
+ #
156
+ # @param context [Object] the context within we want to execute the callback.
157
+ # @param args [Array] an array of arguments that will be available within the execution.
158
+ #
159
+ # @return [void, Object] It may return a value, it depends on the callback.
160
+ #
161
+ # @since 0.1.0
162
+ #
163
+ # @see Lotus::Utils::Callbacks::Chain#run
164
+ def call(context, *args)
165
+ context.instance_exec(*args, &callback)
166
+ end
167
+ end
168
+
169
+ # Method callback
170
+ # It wraps a symbol or a string representing a method name that is implemented by the context within it will be called.
171
+ #
172
+ # @since 0.1.0
173
+ # @private
174
+ class MethodCallback < Callback
175
+ # Executes the callback within the given context and eventually passing the given arguments.
176
+ # Those arguments will be passed according to the arity of the target method.
177
+ #
178
+ # @param context [Object] the context within we want to execute the callback.
179
+ # @param args [Array] an array of arguments that will be available within the execution.
180
+ #
181
+ # @return [void, Object] It may return a value, it depends on the callback.
182
+ #
183
+ # @since 0.1.0
184
+ #
185
+ # @see Lotus::Utils::Callbacks::Chain#run
186
+ def call(context, *args)
187
+ method = context.method(callback)
188
+
189
+ if method.parameters.any?
190
+ method.call(*args)
191
+ else
192
+ method.call
193
+ end
194
+ end
195
+
196
+ protected
197
+ def hash
198
+ callback.hash
199
+ end
200
+
201
+ def eql?(other)
202
+ hash == other.hash
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,59 @@
1
+ require 'lotus/utils/string'
2
+
3
+ module Lotus
4
+ module Utils
5
+ # Class utilities
6
+ # @since 0.1.0
7
+ class Class
8
+ # Loads a class for the given string or pattern.
9
+ #
10
+ # @param name [String] the specific class name or pattern for the class that we want to load
11
+ #
12
+ # @param namespace [Class, Module] the Ruby namespace where we want to perform the lookup.
13
+ #
14
+ # @return [Class, Module] the found Ruby constant.
15
+ #
16
+ # @raise [NameError] if no constant can be found.
17
+ #
18
+ # @since 0.1.0
19
+ #
20
+ # @see Lotus::Utils::String#tokenize
21
+ #
22
+ # @example
23
+ # require 'lotus/utils/class'
24
+ #
25
+ # module App
26
+ # module Service
27
+ # class Endpoint
28
+ # end
29
+ # end
30
+ #
31
+ # class ServiceEndpoint
32
+ # end
33
+ # end
34
+ #
35
+ # # basic usage
36
+ # Lotus::Utils::Class.load!('App::Service') # => App::Service
37
+ #
38
+ # # with explicit namespace
39
+ # Lotus::Utils::Class.load!('Service', App) # => App::Service
40
+ #
41
+ # # with pattern
42
+ # Lotus::Utils::Class.load!('App::Service(::Endpoint|Endpoint)') # => App::Service::Endpoint
43
+ # Lotus::Utils::Class.load!('App::Service(Endpoint|::Endpoint)') # => App::ServiceEndpoint
44
+ #
45
+ # # with missing constant
46
+ # Lotus::Utils::Class.load!('Unknown') # => raises NameError
47
+ def self.load!(name, namespace = Object)
48
+ String.new(name).tokenize do |token|
49
+ begin
50
+ return namespace.const_get(token)
51
+ rescue NameError
52
+ end
53
+ end
54
+
55
+ raise NameError.new(name)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,94 @@
1
+ module Lotus
2
+ module Utils
3
+ # Inheritable class level variable accessors.
4
+ # @since 0.1.0
5
+ #
6
+ # @see Lotus::Utils::ClassAttribute::ClassMethods
7
+ module ClassAttribute
8
+ def self.included(base)
9
+ base.class_eval do
10
+ extend ClassMethods
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ # Defines a class level accessor for the given attribute(s).
16
+ #
17
+ # A value set for a superclass is automatically available by their
18
+ # subclasses, unless a different value is explicitely set within the
19
+ # inheritance chain.
20
+ #
21
+ # @param attributes [Array<Symbol>] a single or multiple attribute name(s)
22
+ #
23
+ # @return [void]
24
+ #
25
+ # @since 0.1.0
26
+ #
27
+ # @example
28
+ # require 'lotus/utils/class_attribute'
29
+ #
30
+ # class Vehicle
31
+ # include Lotus::Utils::ClassAttribute
32
+ # class_attribute :engines, :wheels
33
+ #
34
+ # self.engines = 0
35
+ # self.wheels = 0
36
+ # end
37
+ #
38
+ # class Car < Vehicle
39
+ # self.engines = 1
40
+ # self.wheels = 4
41
+ # end
42
+ #
43
+ # class Airplane < Vehicle
44
+ # self.engines = 4
45
+ # self.wheels = 16
46
+ # end
47
+ #
48
+ # class SmallAirplane < Airplane
49
+ # self.engines = 2
50
+ # self.wheels = 8
51
+ # end
52
+ #
53
+ # Vehicle.engines # => 0
54
+ # Vehicle.wheels # => 0
55
+ #
56
+ # Car.engines # => 1
57
+ # Car.wheels # => 4
58
+ #
59
+ # Airplane.engines # => 4
60
+ # Airplane.wheels # => 16
61
+ #
62
+ # SmallAirplane.engines # => 2
63
+ # SmallAirplane.wheels # => 8
64
+ def class_attribute(*attributes)
65
+ (class << self; self; end).class_eval do
66
+ attr_accessor *attributes
67
+ end
68
+
69
+ class_attributes.merge(attributes)
70
+ end
71
+
72
+ protected
73
+ # @see Class#inherited
74
+ def inherited(subclass)
75
+ class_attributes.each do |attr|
76
+ value = send(attr)
77
+ value = value.dup rescue value
78
+ subclass.class_attribute attr
79
+ subclass.send("#{attr}=", value)
80
+ end
81
+
82
+ super
83
+ end
84
+
85
+ private
86
+ # Class accessor for class attributes.
87
+ # @private
88
+ def class_attributes
89
+ @class_attributes ||= Set.new
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,43 @@
1
+ module Lotus
2
+ module Utils
3
+ # Hash on steroids
4
+ # @since 0.1.0
5
+ class Hash < ::Hash
6
+ # Initialize the hash
7
+ #
8
+ # @param hash [::Hash, Hash] the value we want to use to initialize this instance
9
+ #
10
+ # @return [Hash] self
11
+ #
12
+ # @since 0.1.0
13
+ def initialize(hash = {})
14
+ merge! hash
15
+ end
16
+
17
+ # Convert in-place all the keys to Symbol instances, nested hashes are converted too.
18
+ #
19
+ # @return [Hash] self
20
+ #
21
+ # @since 0.1.0
22
+ #
23
+ # @example
24
+ # require 'lotus/utils/hash'
25
+ #
26
+ # hash = Lotus::Utils::Hash.new 'a' => 23, 'b' => { 'c' => ['x','y','z'] }
27
+ # hash.symbolize!
28
+ #
29
+ # hash.keys # => [:a, :b]
30
+ # hash.inspect # => {:a=>23, :b=>{:c=>["x", "y", "z"]}}
31
+ def symbolize!
32
+ keys.each do |k|
33
+ v = delete(k)
34
+ v = Hash.new(v).symbolize! if v.is_a?(::Hash)
35
+
36
+ self[k.to_sym] = v
37
+ end
38
+
39
+ self
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ module Lotus
2
+ module Utils
3
+ # IO utils
4
+ #
5
+ # @since 0.1.0
6
+ class IO
7
+ # Decreases the level of verbosity, during the execution of the given block.
8
+ #
9
+ # Revised version of ActiveSupport's `Kernel.with_warnings` implementation
10
+ # @see https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/kernel/reporting.rb#L25
11
+ #
12
+ # @param blk [Proc] the block of code that generates warnings.
13
+ #
14
+ # @return [void]
15
+ #
16
+ # @since 0.1.0
17
+ #
18
+ # @example
19
+ # require 'lotus/utils/io'
20
+ #
21
+ # class Test
22
+ # TEST_VALUE = 'initial'
23
+ # end
24
+ #
25
+ # Lotus::Utils::IO.silence_warnings do
26
+ # Test::TEST_VALUE = 'redefined'
27
+ # end
28
+ def self.silence_warnings(&blk)
29
+ old_verbose, $VERBOSE = $VERBOSE, nil
30
+ blk.call
31
+ ensure
32
+ $VERBOSE = old_verbose
33
+ end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,84 @@
1
+ module Lotus
2
+ module Utils
3
+ # Prefixed string
4
+ #
5
+ # @since 0.1.0
6
+ class PathPrefix < ::String
7
+ # Initialize the path prefix
8
+ #
9
+ # @param string [::String] the prefix value
10
+ # @param separator [::String] the separator used between tokens
11
+ #
12
+ # @return [PathPrefix] self
13
+ #
14
+ # @since 0.1.0
15
+ def initialize(string = nil, separator = '/')
16
+ @separator = separator
17
+ super(string.to_s)
18
+ end
19
+
20
+ # Joins self with the given token.
21
+ # It cleanups the all the `separator` repetitions.
22
+ #
23
+ # @param string [::String] the token we want to join
24
+ #
25
+ # @return [::String] the joined string
26
+ #
27
+ # @since 0.1.0
28
+ #
29
+ # @example
30
+ # require 'lotus/utils/path_prefix'
31
+ #
32
+ # path_prefix = Lotus::Utils::PathPrefix.new '/posts'
33
+ # path_prefix.join 'new' # => '/posts/new'
34
+ # path_prefix.join '/new' # => '/posts/new'
35
+ #
36
+ # path_prefix = Lotus::Utils::PathPrefix.new 'posts'
37
+ # path_prefix.join 'new' # => '/posts/new'
38
+ # path_prefix.join '/new' # => '/posts/new'
39
+ def join(string)
40
+ absolutize relative_join(string)
41
+ end
42
+
43
+ # Joins self with the given token, without prefixing it with `separator`.
44
+ # It cleanups the all the `separator` repetitions.
45
+ #
46
+ # @param string [::String] the token we want to join
47
+ # @param separator [::String] the separator used between tokens
48
+ #
49
+ # @return [::String] the joined string
50
+ #
51
+ # @since 0.1.0
52
+ #
53
+ # @example
54
+ # require 'lotus/utils/path_prefix'
55
+ #
56
+ # path_prefix = Lotus::Utils::PathPrefix.new 'posts'
57
+ # path_prefix.relative_join 'new' # => 'posts/new'
58
+ # path_prefix.relative_join 'new', '_' # => 'posts_new'
59
+ def relative_join(string, separator = @separator)
60
+ separator = separator || @separator
61
+ relativize [self, string].join(separator), separator
62
+ end
63
+
64
+ private
65
+ attr_reader :separator
66
+
67
+ def absolutize(string)
68
+ string.tap do |s|
69
+ s.insert(0, separator) unless absolute?(s)
70
+ end
71
+ end
72
+
73
+ def absolute?(string)
74
+ string.start_with?(separator)
75
+ end
76
+
77
+ def relativize(string, separator = @separator)
78
+ string.
79
+ gsub(%r{(?<!:)#{ separator * 2 }}, separator).
80
+ gsub(%r{\A#{ separator }}, '')
81
+ end
82
+ end
83
+ end
84
+ end