hoodie 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,118 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ #
5
+ # Copyright (C) 2014 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'hoodie/stash/disk_store' unless defined?(DiskStash)
21
+ require 'hoodie/stash/mem_store' unless defined?(MemStash)
22
+
23
+ # Define the basic cache and default store objects
24
+ module Stash
25
+
26
+ # check if we're using a version if Ruby that supports caller_locations
27
+ NEW_CALL = Kernel.respond_to? 'caller_locations'
28
+
29
+ class << self
30
+ # insert a helper .new() method for creating a new object
31
+ #
32
+ def new(*args)
33
+ self::Cache.new(*args)
34
+ end
35
+
36
+ # helper to get the calling function name
37
+ #
38
+ def caller_name
39
+ NEW_CALL ? caller_locations(2, 1).first.label : caller[1][/`([^']*)'/, 1]
40
+ end
41
+ end
42
+
43
+ # Default store type
44
+ DEFAULT_STORE = MemStash::Cache
45
+
46
+ # Key/value cache store
47
+ class Cache
48
+ # @return [Hash] of the mem stash cache hash store
49
+ #
50
+ attr_reader :store
51
+
52
+ # Initializes a new empty store
53
+ #
54
+ def initialize(params = {})
55
+ params = { store: params } unless params.is_a? Hash
56
+ @store = params.fetch(:store) { Stash::DEFAULT_STORE.new }
57
+ end
58
+
59
+ # Clear the whole stash store or the value of a key
60
+ #
61
+ # @param key [Symbol, String] (optional) representing the key to
62
+ # clear.
63
+ #
64
+ # @return nothing.
65
+ #
66
+ def clear!(key = nil)
67
+ key = key.to_sym unless key.nil?
68
+ @store.clear! key
69
+ end
70
+
71
+ # Retrieves the value for a given key, if nothing is set,
72
+ # returns KeyError
73
+ #
74
+ # @param key [Symbol, String] representing the key
75
+ #
76
+ # @raise [KeyError] if no such key found
77
+ #
78
+ # @return [Hash, Array, String] value for key
79
+ #
80
+ def [](key = nil)
81
+ key ||= Stash.caller_name
82
+ fail KeyError, 'Key not cached' unless include? key.to_sym
83
+ @store[key.to_sym]
84
+ end
85
+
86
+ # Retrieves the value for a given key, if nothing is set,
87
+ # run the code, cache the result, and return it
88
+ #
89
+ # @param key [Symbol, String] representing the key
90
+ # @param block [&block] that returns the value to set (optional)
91
+ #
92
+ # @return [Hash, Array, String] value for key
93
+ #
94
+ def cache(key = nil, &code)
95
+ key ||= Stash.caller_name
96
+ @store[key.to_sym] ||= code.call
97
+ end
98
+
99
+ # return the size of the store as an integer
100
+ #
101
+ # @return [Fixnum]
102
+ #
103
+ def size
104
+ @store.size
105
+ end
106
+
107
+ # return a boolean indicating presence of the given key in the store
108
+ #
109
+ # @param key [Symbol, String] a string or symbol representing the key
110
+ #
111
+ # @return [TrueClass, FalseClass]
112
+ #
113
+ def include?(key = nil)
114
+ key ||= Stash.caller_name
115
+ @store.include? key.to_sym
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,151 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ #
5
+ # Copyright (C) 2014 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'tmpdir'
21
+
22
+ module DiskStash
23
+ # Disk stashing method variable caching hash, string, array store.
24
+ class Cache
25
+ include Enumerable
26
+
27
+ # @return [String] location of DiskStash::Cache.store
28
+ #
29
+ attr_reader :store
30
+
31
+ # Initializes a new disked backed stash hash cache store.
32
+ #
33
+ # @param path [String] location for stash store cache.
34
+ #
35
+ # @return nothing.
36
+ #
37
+ def initialize(store = file_store)
38
+ @store = store
39
+ ensure_store_directory
40
+ end
41
+
42
+ # Clear the whole stash or the value of a key
43
+ #
44
+ # @param key [Symbol, String] (optional) string or symbol
45
+ # representing the key to clear
46
+ #
47
+ # @return [Hash] with a key, return the value it had, without
48
+ # returns {}
49
+ #
50
+ def clear!(key = nil)
51
+ if key.nil?
52
+ ::Dir[::File.join(store, '*.cache')].each do |file|
53
+ ::File.delete(file)
54
+ end
55
+ else
56
+ ::File.delete(cache_file(key)) if ::File.exists?(cache_file(key))
57
+ end
58
+ end
59
+
60
+ # Retrieves the value for a given key, if nothing is set,
61
+ # returns KeyError
62
+ #
63
+ # @param key [Symbol, String] representing the key
64
+ #
65
+ # @raise [KeyError] if no such key found
66
+ #
67
+ # @return [Hash, Array, String] value for key
68
+ #
69
+ def [](key)
70
+ if key.is_a? Array
71
+ hash = {}
72
+ key.each do |k|
73
+ hash[k] = Marshal::load(read_cache_file(k))
74
+ end
75
+ hash unless hash.empty?
76
+ else
77
+ Marshal::load(read_cache_file(key))
78
+ end
79
+ rescue Errno::ENOENT
80
+ nil # key hasn't been created
81
+ end
82
+
83
+ # Store the given value with the given key, either an an argument
84
+ # or block. If a previous value was set it will be overwritten
85
+ # with the new value.
86
+ # #
87
+ # @param key [Symbol, String] representing the key
88
+ # @param value [Object] that represents the value (optional)
89
+ # @param block [&block] that returns the value to set (optional)
90
+ #
91
+ # @return nothing.
92
+ #
93
+ def []=(key, value)
94
+ write_cache_file(key, Marshal::dump(value))
95
+ end
96
+
97
+ # returns path to cache file with 'key'
98
+ def cache_file key
99
+ ::File.join(store, key.to_s + '.cache')
100
+ end
101
+
102
+ private # P R O P R I E T À P R I V A T A divieto di accesso
103
+
104
+ # return Chef tmpfile path if running under Chef, else return OS
105
+ # temp path. On Winders Dir.tmpdir returns the correct path.
106
+ #
107
+ def file_store
108
+ tmp = defined?(Chef::Config) ? Chef::Config[:file_cache_path] : Dir.tmpdir
109
+ if OS.windows?
110
+ win_friendly_path(::File.join(tmp, '._stash'))
111
+ else
112
+ '_stash'
113
+ # ::File.join(tmp, '._stash')
114
+ end
115
+ end
116
+
117
+ # returns windows friendly version of the provided path, ensures
118
+ # backslashes are used everywhere
119
+ #
120
+ def win_friendly_path(path)
121
+ system_drive = ENV['SYSTEMDRIVE'] ? ENV['SYSTEMDRIVE'] : ""
122
+ path = ::File.join(system_drive, path)
123
+ path.gsub!(::File::SEPARATOR, (::File::ALT_SEPARATOR || '\\'))
124
+ end
125
+
126
+ def write_cache_file(key, content)
127
+ f = ::File.open(cache_file(key), 'w+' )
128
+ f.flock(::File::LOCK_EX)
129
+ f.write(content)
130
+ f.close
131
+ content
132
+ end
133
+
134
+ def read_cache_file(key)
135
+ f = ::File.open(cache_file(key), 'r')
136
+ f.flock(::File::LOCK_SH)
137
+ out = f.read
138
+ f.close
139
+ out
140
+ end
141
+
142
+ def read_cache_mtime(key)
143
+ nil unless ::File.exists?(cache_file(key))
144
+ ::File.mtime(cache_file(key))
145
+ end
146
+
147
+ def ensure_store_directory
148
+ ::Dir.mkdir(store) unless ::File.directory?(store)
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,150 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ #
5
+ # Copyright (C) 2014 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module MemStash
21
+ # Basic cache object stash store (uses a Hash)
22
+ class Cache
23
+ include Enumerable
24
+
25
+ # @return [Hash] of the mem stash cache hash store
26
+ #
27
+ attr_reader :store
28
+
29
+ # Initializes a new store object.
30
+ #
31
+ # @param data [Hash] (optional) data to load into the stash.
32
+ #
33
+ # @return nothing.
34
+ #
35
+ def initialize(_ = {})
36
+ @store = {}
37
+ end
38
+
39
+ # Clear the whole stash store or the value of a key
40
+ #
41
+ # @param key [Symbol, String] (optional) representing the key to
42
+ # clear.
43
+ #
44
+ # @return nothing.
45
+ #
46
+ def clear!(key = nil)
47
+ key.nil? ? @store.clear : @store.delete(key)
48
+ end
49
+
50
+ # Retrieves the value for a given key, if nothing is set,
51
+ # returns KeyError
52
+ #
53
+ # @param key [Symbol, String] representing the key
54
+ #
55
+ # @raise [KeyError] if no such key found
56
+ #
57
+ # @return [Hash, Array, String] value for key
58
+ #
59
+ def [](key)
60
+ @store[key]
61
+ end
62
+
63
+ # Store the given value with the given key, either an an argument
64
+ # or block. If a previous value was set it will be overwritten
65
+ # with the new value.
66
+ #
67
+ # @example store a value
68
+ #
69
+ # stash.set('name') { 'Trigster' }
70
+ # => "Trigster"
71
+ # stash[:cash] = 'in the hash stash cache store'
72
+ # => "in the hash stash cache store"
73
+ # data = { id: 'trig', name: 'Trigster Jay', passwd: 'f00d' }
74
+ # stash[:juser] = data
75
+ # => {
76
+ # :id => "trig",
77
+ # :name => "Trigster Jay",
78
+ # :passwd => "f00d"
79
+ # }
80
+ #
81
+ # @param key [Symbol, String] string or symbol representing the key
82
+ # @param value [Object] any object that represents the value (optional)
83
+ # @param block [&block] that returns the value to set (optional)
84
+ #
85
+ # @return nothing.
86
+ #
87
+ def []=(key, value)
88
+ @store[key] = value
89
+ end
90
+
91
+ # Iterates over all key-value pairs.
92
+ #
93
+ # @param block [&block] that will receive the key/value of each pair
94
+ #
95
+ # @yield the string key and value.
96
+ #
97
+ def each(&block)
98
+ @store.each { |k, v| yield(k, v) }
99
+ end
100
+
101
+ # Loads a hash of data into the stash.
102
+ #
103
+ # @param hash [Hash] of data with either String or Symbol keys.
104
+ #
105
+ # @return nothing.
106
+ #
107
+ def load(data)
108
+ data.each do |key, value|
109
+ @store[key] = value
110
+ end
111
+ end
112
+
113
+ # return the size of the store as an integer
114
+ #
115
+ # @return [Fixnum]
116
+ #
117
+ def size
118
+ @store.size
119
+ end
120
+
121
+ # return a boolean indicating presence of the given key in the store
122
+ #
123
+ # @param key [Symbol, String] a string or symbol representing the key
124
+ #
125
+ # @return [TrueClass, FalseClass]
126
+ #
127
+ def include?(key)
128
+ @store.include? key
129
+ end
130
+ alias_method :key?, :include?
131
+
132
+ # return a boolean indicating presence of the given value in the store
133
+ #
134
+ # @param value [String] a string representing the value
135
+ #
136
+ # @return [TrueClass, FalseClass]
137
+ #
138
+ def value?(value)
139
+ @store.value? value
140
+ end
141
+
142
+ # return all keys in the store as an array
143
+ #
144
+ # @return [Array<String, Symbol>] all the keys in store
145
+ #
146
+ def keys
147
+ @store.keys
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,134 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ #
5
+ # Copyright (C) 2014 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module Hoodie
21
+ # Returns an aligned_string of text relative to the size of the terminal
22
+ # window. If a line in the string exceeds the width of the terminal window
23
+ # the line will be chopped off at the whitespace chacter closest to the
24
+ # end of the line and prepended to the next line, keeping all indentation.
25
+ #
26
+ # The terminal size is detected by default, but custom line widths can
27
+ # passed. All strings will also be left aligned with 5 whitespace characters
28
+ # by default.
29
+ def self.align_text(text, console_cols = nil, preamble = 5)
30
+ unless console_cols
31
+ console_cols = terminal_dimensions[0]
32
+
33
+ # if unknown size we default to the typical unix default
34
+ console_cols = 80 if console_cols == 0
35
+ end
36
+
37
+ console_cols -= preamble
38
+
39
+ # Return unaligned text if console window is too small
40
+ return text if console_cols <= 0
41
+
42
+ # If console is 0 this implies unknown so we assume the common
43
+ # minimal unix configuration of 80 characters
44
+ console_cols = 80 if console_cols <= 0
45
+
46
+ text = text.split("\n")
47
+ piece = ''
48
+ whitespace = 0
49
+
50
+ text.each_with_index do |line, i|
51
+ whitespace = 0
52
+
53
+ while whitespace < line.length && line[whitespace].chr == ' '
54
+ whitespace += 1
55
+ end
56
+
57
+ # If the current line is empty, indent it so that a snippet
58
+ # from the previous line is aligned correctly.
59
+ if line == ""
60
+ line = (" " * whitespace)
61
+ end
62
+
63
+ # If text was snipped from the previous line, prepend it to the
64
+ # current line after any current indentation.
65
+ if piece != ''
66
+ # Reset whitespaces to 0 if there are more whitespaces than there are
67
+ # console columns
68
+ whitespace = 0 if whitespace >= console_cols
69
+
70
+ # If the current line is empty and being prepended to, create a new
71
+ # empty line in the text so that formatting is preserved.
72
+ if text[i + 1] && line == (" " * whitespace)
73
+ text.insert(i + 1, "")
74
+ end
75
+
76
+ # Add the snipped text to the current line
77
+ line.insert(whitespace, "#{piece} ")
78
+ end
79
+
80
+ piece = ''
81
+
82
+ # Compare the line length to the allowed line length.
83
+ # If it exceeds it, snip the offending text from the line
84
+ # and store it so that it can be prepended to the next line.
85
+ if line.length > (console_cols + preamble)
86
+ reverse = console_cols
87
+
88
+ while line[reverse].chr != ' '
89
+ reverse -= 1
90
+ end
91
+
92
+ piece = line.slice!(reverse, (line.length - 1)).lstrip
93
+ end
94
+
95
+ # If a snippet exists when all the columns in the text have been
96
+ # updated, create a new line and append the snippet to it, using
97
+ # the same left alignment as the last line in the text.
98
+ if piece != '' && text[i+1].nil?
99
+ text[i+1] = "#{' ' * (whitespace)}#{piece}"
100
+ piece = ''
101
+ end
102
+
103
+ # Add the preamble to the line and add it to the text
104
+ line = ((' ' * preamble) + line)
105
+ text[i] = line
106
+ end
107
+
108
+ text.join("\n")
109
+ end
110
+
111
+ # Figures out the columns and lines of the current tty
112
+ #
113
+ # Returns [0, 0] if it can't figure it out or if you're
114
+ # not running on a tty
115
+ def self.terminal_dimensions(stdout = STDOUT, environment = ENV)
116
+ return [0, 0] unless stdout.tty?
117
+
118
+ return [80, 40] if Util.windows?
119
+
120
+ if environment["COLUMNS"] && environment["LINES"]
121
+ return [environment["COLUMNS"].to_i, environment["LINES"].to_i]
122
+
123
+ elsif environment["TERM"] && command_in_path?("tput")
124
+ return [`tput cols`.to_i, `tput lines`.to_i]
125
+
126
+ elsif command_in_path?('stty')
127
+ return `stty size`.scan(/\d+/).map {|s| s.to_i }
128
+ else
129
+ return [0, 0]
130
+ end
131
+ rescue
132
+ [0, 0]
133
+ end
134
+ end