xdg 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,220 @@
1
+ module XDG
2
+
3
+ # Base Directory Standard
4
+ class BaseDir
5
+
6
+ # Try to get information from Ruby's install configuration.
7
+ require 'rbconfig'
8
+
9
+ sysconfdir = ::Config::CONFIG['sysconfdir'] || '/etc'
10
+ datadir = ::Config::CONFIG['datadir'] || '/usr/share'
11
+
12
+ # Standard defaults for locations.
13
+ DEFAULTS = {
14
+ 'XDG_DATA_HOME' => ['~/.local/share'],
15
+ 'XDG_DATA_DIRS' => ['/usr/local/share', datadir],
16
+ 'XDG_CONFIG_HOME' => ['~/.config'],
17
+ 'XDG_CONFIG_DIRS' => [File.join(sysconfdir,'xdg'), sysconfdir],
18
+ 'XDG_CACHE_HOME' => ['~/.cache'],
19
+ 'XDG_CACHE_DIRS' => ['/tmp']
20
+ }
21
+
22
+ # BaseDir iterates over directory paths.
23
+ include Enumerable
24
+
25
+ # Shortcut for `BaseDir.new`.
26
+ def self.[](*env)
27
+ new(*env)
28
+ end
29
+
30
+ # Initialize new instance of BaseDir class.
31
+ def initialize(*env)
32
+ @environment_variables = []
33
+ env.each do |v|
34
+ v = v.to_s.upcase
35
+ if v !~ /_/
36
+ @environment_variables << 'XDG_' + v + '_HOME'
37
+ @environment_variables << 'XDG_' + v + '_DIRS'
38
+ else
39
+ @environment_variables << 'XDG_' + v
40
+ end
41
+ end
42
+ end
43
+
44
+ # The environment variables being referenced.
45
+ #
46
+ # @return [Array] list of XDG environment variable names
47
+ def environment_variables
48
+ @environment_variables
49
+ end
50
+
51
+ # Returns a complete list of directories.
52
+ def to_a
53
+ environment_variables.map do |v|
54
+ if paths = ENV[v]
55
+ dirs = paths.split(/[:;]/)
56
+ else
57
+ dirs = DEFAULTS[v]
58
+ end
59
+ dirs.map{ |path| expand(path) }
60
+ end.flatten
61
+ end
62
+
63
+ # BaseDir is essentially an array.
64
+ alias_method :to_ary, :to_a
65
+
66
+ # Number of directory paths.
67
+ def size
68
+ to_a.size
69
+ end
70
+
71
+ # Iterate of each directory.
72
+ def each(&block)
73
+ to_a.each(&block)
74
+ end
75
+
76
+ # Returns a complete list of directories.
77
+ def list
78
+ to_a
79
+ end
80
+
81
+ # List of directories as Pathanme objects.
82
+ #
83
+ # @return [Array<Pathname>] list of directories as Pathname objects
84
+ def paths
85
+ map{ |dir| Pathname.new(dir) }
86
+ end
87
+
88
+ # Return array of matching files or directories
89
+ # in any of the resource locations, starting with
90
+ # the home directory and searching outward into
91
+ # system directories.
92
+ #
93
+ # Unlike #select, this doesn't take a block and each
94
+ # additional glob argument is treated as a logical-or.
95
+ #
96
+ # XDG[:DATA].glob("stick/*.rb", "stick/*.yaml")
97
+ #
98
+ def glob(*glob_and_flags)
99
+ glob, flags = *parse_arguments(*glob_and_flags)
100
+ find = []
101
+ list.each do |dir|
102
+ glob.each do |pattern|
103
+ find.concat(Dir.glob(File.join(dir, pattern), flags))
104
+ end
105
+ end
106
+ find.uniq
107
+ end
108
+
109
+ # Return array of matching files or directories
110
+ # in any of the resource locations, starting with
111
+ # the home directory and searching outward into
112
+ # system directories.
113
+ #
114
+ # String parameters are joined into a pathname
115
+ # while Integers and Symbols treated as flags.
116
+ #
117
+ # For example, the following are equivalent:
118
+ #
119
+ # XDG::BaseDir[:DATA,:HOME].select('stick/units', File::FNM_CASEFOLD)
120
+ #
121
+ # XDG::BaseDir[:DATA,:HOME].select('stick', 'units', :casefold)
122
+ #
123
+ def select(*glob_and_flags, &block)
124
+ glob, flag = *parse_arguments(*glob_and_flags)
125
+ find = []
126
+ list.each do |dir|
127
+ path = File.join(dir, *glob)
128
+ hits = Dir.glob(path, flag)
129
+ hits = hits.select(&block) if block_given?
130
+ find.concat(hits)
131
+ end
132
+ find.uniq
133
+ end
134
+
135
+ # Find a file or directory. This works just like #select
136
+ # except that it returns the first match found.
137
+ #
138
+ # TODO: It would be more efficient to traverse the dirs and use #fnmatch.
139
+ def find(*glob_and_flags, &block)
140
+ glob, flag = *parse_arguments(*glob_and_flags)
141
+ find = nil
142
+ list.each do |dir|
143
+ path = File.join(dir, *glob)
144
+ hits = Dir.glob(path, flag)
145
+ hits = hits.select(&block) if block_given?
146
+ find = hits.first
147
+ break if find
148
+ end
149
+ find
150
+ end
151
+
152
+ # @return [String] envinronment values.
153
+ def to_s
154
+ environment_variables.map{ |v| ENV[v] || DEFAULTS[v] }.join(':')
155
+ end
156
+
157
+ # @return [Pathname] pathname of first directory
158
+ def to_path
159
+ Pathname.new(to_s)
160
+ end
161
+
162
+ #
163
+ def env
164
+ environment_variables.map{ |v| ENV[v] }.join(':')
165
+ end
166
+
167
+ #
168
+ attr :subdirectory
169
+
170
+ #
171
+ def subdirectory=(path)
172
+ @subdirectory = path.to_s
173
+ end
174
+
175
+ #
176
+ def with_subdirectory(path)
177
+ @subdirectory = path if path
178
+ self
179
+ end
180
+
181
+ private
182
+
183
+ def parse_arguments(*glob_and_flags)
184
+ glob, flags = *glob_and_flags.partition{ |e| String===e }
185
+ glob = ['**/*'] if glob.empty?
186
+ flag = flags.inject(0) do |m, f|
187
+ if Symbol === f
188
+ m + File::const_get("FNM_#{f.to_s.upcase}")
189
+ else
190
+ m + f.to_i
191
+ end
192
+ end
193
+ return glob, flag
194
+ end
195
+
196
+ #
197
+ def expand(path)
198
+ if subdirectory
199
+ File.expand_path(File.join(path, subdirectory))
200
+ else
201
+ File.expand_path(path)
202
+ end
203
+ end
204
+
205
+ # If Pathname is referenced the library is automatically loaded.
206
+ def self.const_missing(const)
207
+ if const == :Pathname
208
+ require 'pathname'
209
+ ::Pathname
210
+ else
211
+ super(const)
212
+ end
213
+ end
214
+
215
+ end
216
+
217
+ end
218
+
219
+ # Copyright (c) 2008,2011 Thomas Sawyer
220
+ # Distributed under the terms of the APACHE 2.0 license.
@@ -0,0 +1,20 @@
1
+ module XDG
2
+
3
+ # Base directory interface class.
4
+ class BaseDir
5
+
6
+ #
7
+ DEFAULTS['XDG_RESOURCE_HOME'] = ['~/.local']
8
+ DEFAULTS['XDG_RESOURCE_DIRS'] = ['/usr/local','/usr']
9
+
10
+ # Working directory
11
+ # TODO: Not sure about these defaults
12
+ DEFAULTS['XDG_CONFIG_WORK'] = ['.config','config']
13
+ DEFAULTS['XDG_CACHE_WORK'] = ['.tmp','tmp']
14
+ DEFAULTS['XDG_RESOURCE_WORK'] = ['.local']
15
+ end
16
+
17
+ end
18
+
19
+ # Copyright (c) 2008,2011 Thomas Sawyer
20
+ # Distributed under the terms of the APACHE 2.0 license.
@@ -0,0 +1,18 @@
1
+ if RUBY_VERSION > '1.9'
2
+ require_relative 'base_dir'
3
+ else
4
+ require 'xdg/base_dir'
5
+ end
6
+
7
+ $XDG_DATA = XDG::BaseDir.new('DATA')
8
+ $XDG_DATA_HOME = XDG::BaseDir.new('DATA', 'HOME')
9
+ $XDG_DATA_DIRS = XDG::BaseDir.new('DATA', 'DIRS')
10
+
11
+ $XDG_CONFIG = XDG::BaseDir.new('CONFIG')
12
+ $XDG_CONFIG_HOME = XDG::BaseDir.new('CONFIG', 'HOME')
13
+ $XDG_CONFIG_DIRS = XDG::BaseDir.new('CONFIG', 'DIRS')
14
+
15
+ $XDG_CACHE = XDG::BaseDir.new('CACHE')
16
+ $XDG_CACHE_HOME = XDG::BaseDir.new('CACHE', 'HOME')
17
+ $XDG_CACHE_DIRS = XDG::BaseDir.new('CACHE', 'DIRS')
18
+
@@ -0,0 +1,72 @@
1
+ module XDG
2
+ class BaseDir
3
+ # Legacy API can serve as a stop gap until a developer
4
+ # has time to update an program already using XDG.
5
+ #
6
+ # Do NOT use this module for future development!!!
7
+ module Legacy
8
+ #
9
+ require 'xdg'
10
+ require 'xdg/base_dir/extended'
11
+
12
+ #
13
+ extend self
14
+
15
+ #
16
+ def home
17
+ File.expand_path('~')
18
+ end
19
+
20
+ #
21
+ def data
22
+ obj = XDG['DATA']
23
+ class << obj
24
+ def home
25
+ XDG['DATA_HOME'].to_a.first
26
+ end
27
+ def dirs
28
+ XDG['DATA_DIRS'].to_a
29
+ end
30
+ end
31
+ return obj
32
+ end
33
+
34
+ #
35
+ def config
36
+ obj = XDG['CONFIG']
37
+ class << obj
38
+ def home
39
+ XDG['CONFIG_HOME'].to_a.first
40
+ end
41
+ def dirs
42
+ XDG['CONFIG_DIRS'].to_a
43
+ end
44
+ def work
45
+ XDG['CONFIG_WORK'].to_a
46
+ end
47
+ end
48
+ return obj
49
+ end
50
+
51
+ #
52
+ def cache
53
+ obj = XDG['CACHE']
54
+ class << obj
55
+ def home
56
+ XDG['CACHE_HOME'].to_a.first
57
+ end
58
+ def dirs
59
+ XDG['CACHE_DIRS'].to_a
60
+ end
61
+ def work
62
+ XDG['CACHE_WORK'].to_a
63
+ end
64
+ end
65
+ return obj
66
+ end
67
+
68
+ end
69
+ end
70
+
71
+ extend BaseDir::Legacy
72
+ end
@@ -0,0 +1,84 @@
1
+ module XDG
2
+ class BaseDir
3
+ #
4
+ # The BaseDir::Mixin module can be used to add XDG base directory
5
+ # methods to your own classes.
6
+ #
7
+ # class MyAppConfig
8
+ # include XDG::BaseDir::Mixin
9
+ #
10
+ # def subdirectory
11
+ # 'myapp'
12
+ # end
13
+ # end
14
+ #
15
+ # c = MyAppConfig.new
16
+ #
17
+ # c.config.home.to_s #=> '~/.config/myapp'
18
+ #
19
+ module Mixin
20
+
21
+ # @todo do we need this?
22
+ extend self
23
+
24
+ # Override this method to change the subdirectory of the mixin.
25
+ def subdirectory
26
+ nil
27
+ end
28
+
29
+ #
30
+ def home
31
+ File.expand_path('~')
32
+ end
33
+
34
+ #
35
+ def data
36
+ obj = XDG['DATA'].with_subdirectory(subdirectory)
37
+ class << obj
38
+ def home
39
+ XDG['DATA_HOME'].with_subdirectory(subdirectory)
40
+ end
41
+ def dirs
42
+ XDG['DATA_DIRS'].with_subdirectory(subdirectory)
43
+ end
44
+ end
45
+ return obj
46
+ end
47
+
48
+ #
49
+ def config
50
+ obj = XDG['CONFIG'].with_subdirectory(subdirectory)
51
+ class << obj
52
+ def home
53
+ XDG['CONFIG_HOME'].with_subdirectory(subdirectory)
54
+ end
55
+ def dirs
56
+ XDG['CONFIG_DIRS'].with_subdirectory(subdirectory)
57
+ end
58
+ def work
59
+ XDG['CONFIG_WORK'].with_subdirectory(subdirectory)
60
+ end
61
+ end
62
+ return obj
63
+ end
64
+
65
+ #
66
+ def cache
67
+ obj = XDG['CACHE'].with_subdirectory(subdirectory)
68
+ class << obj
69
+ def home
70
+ XDG['CACHE_HOME'].with_subdirectory(subdirectory)
71
+ end
72
+ def dirs
73
+ XDG['CACHE_DIRS'].with_subdirectory(subdirectory)
74
+ end
75
+ def work
76
+ XDG['CACHE_WORK'].with_subdirectory(subdirectory)
77
+ end
78
+ end
79
+ return obj
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ module XDG
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,77 @@
1
+ = XDG Base Directory Standard
2
+
3
+ The 2.0 API is much a great deal more concise than the original
4
+ 0.0+ and 1.0+ APIs. It consists primarily of a single
5
+ interface method `XDG[]`. Yet all the functionality of the older
6
+ API remain and then some.
7
+
8
+ First we need to require the library.
9
+
10
+ require 'xdg'
11
+
12
+ In the applique we have setup a fake root directory with
13
+ coorepsonding environment settings to use as test fixtures.
14
+
15
+ == Data Paths
16
+
17
+ === Home
18
+
19
+ XDG['DATA_HOME'].env.assert == ENV['XDG_DATA_HOME'].to_s
20
+ XDG['DATA_HOME'].environment_variables.assert == ['XDG_DATA_HOME']
21
+
22
+ Looking at the data home location by default it should be point to
23
+ our joe user's home directory under `.local/share`.
24
+
25
+ XDG['DATA_HOME'].to_a.assert == [$froot + 'home/joe/.local/share']
26
+
27
+ === Dirs
28
+
29
+ XDG['DATA_DIRS'].env.assert == ENV['XDG_DATA_DIRS'].to_s
30
+ XDG['DATA_DIRS'].environment_variables.assert == ['XDG_DATA_DIRS']
31
+
32
+ Looking at the system data locations
33
+
34
+ XDG['DATA_DIRS'].to_a.assert == [$froot + 'usr/share']
35
+
36
+ === Combined
37
+
38
+ XDG['DATA'].environment_variables.assert == ['XDG_DATA_HOME', 'XDG_DATA_DIRS']
39
+
40
+ Lookking at both data location combined
41
+
42
+ XDG['DATA'].to_a.assert == [$froot + 'home/joe/.local/share', $froot + 'usr/share']
43
+
44
+
45
+ == Config Paths
46
+
47
+ === Home
48
+
49
+ XDG['CONFIG_HOME'].env.assert == ENV['XDG_CONFIG_HOME'].to_s
50
+ XDG['CONFIG_HOME'].to_a.assert == [$froot + 'home/joe/.config']
51
+
52
+ === Dirs
53
+
54
+ XDG['CONFIG_DIRS'].env.assert == ENV['XDG_CONFIG_DIRS'].to_s
55
+ XDG['CONFIG_DIRS'].to_a.assert == [$froot + 'etc/xdg', $froot + 'etc']
56
+
57
+ === Combined
58
+
59
+ XDG['CONFIG'].to_a.assert == [$froot + 'home/joe/.config', $froot + 'etc/xdg', $froot + 'etc']
60
+
61
+
62
+ == Cache Paths
63
+
64
+ === Home
65
+
66
+ XDG['CACHE_HOME'].env.assert == ENV['XDG_CACHE_HOME'].to_s
67
+ XDG['CACHE_HOME'].to_a.assert == [$froot + 'home/joe/.cache']
68
+
69
+ === Dirs
70
+
71
+ XDG['CACHE_DIRS'].env.assert == ENV['XDG_CACHE_DIRS'].to_s
72
+ XDG['CACHE_DIRS'].to_a.assert == [$froot + 'tmp']
73
+
74
+ === Combined
75
+
76
+ XDG['CACHE'].to_a.assert == [$froot + 'home/joe/.cache', $froot + 'tmp']
77
+