lotus-utils 0.0.0 → 0.1.0

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 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