dotsmack 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +23 -0
  3. data/README.md +104 -0
  4. data/lib/dotsmack.rb +241 -0
  5. data/lib/version.rb +6 -0
  6. metadata +257 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3dffb1c482c853c56be3b48b344e5dcd3f45347c
4
+ data.tar.gz: 8e641d9d1d463b9a92d00aac08e97020011b3e58
5
+ SHA512:
6
+ metadata.gz: 6437eb61b4b3e1828b8a940f89d82e2a34a2a0dc501d6d5c65ea604d66ca5ce0d483f33229605176a84ec351fac2364877f35e3bddd9885f0ed5b9c71faa8db0
7
+ data.tar.gz: 7f734c28a591e72dd53e091e0c85f322e70a730af83d8e95c1fbfc166ef7866249c03b4c8f3b7de0dd6d12b2e282f37ce75587ff431bd2ae12ad95baf3e49bda
@@ -0,0 +1,23 @@
1
+ # FreeBSD License
2
+
3
+ # Copyright 2014 Andrew Pennebaker. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification,
6
+ are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation and/or
12
+ other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
17
+ SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,104 @@
1
+ # dotsmack - a library for modern, per-directory dotfile configuration
2
+
3
+ # HOMEPAGE
4
+
5
+ https://github.com/mcandre/dotsmack
6
+
7
+ # RUBYGEMS
8
+
9
+ https://rubygems.org/gems/dotsmack
10
+
11
+ # ABOUT
12
+
13
+ Dotsmack is a Ruby library for adding modern dotfile customization to your Ruby applications.
14
+
15
+ * Recursive file scanning, like `jshint .`
16
+ * dotignore files - [fnmatch](http://man.cx/fnmatch) syntax, like `.gitignore`
17
+ * dotconfig files - any format (getoptlong, YAML, JSON, ...)
18
+ * Searches for dotfiles in `.`, `..`, etc., up to `$HOME`.
19
+
20
+ # EXAMPLES
21
+
22
+ ```
23
+ $ tree -a examples/twitch/
24
+ examples/twitch/
25
+ ├── bin
26
+ │   └── twitch
27
+ └── test
28
+ ├── .twitchignore
29
+ ├── a-tale-of-two-cities.txt
30
+ ├── embiggened
31
+ │   └── beginning-programming-with-java-for-dummies.txt
32
+ ├── fahrenheit-451.txt
33
+ ├── shortened
34
+ │   └── beginning-programming-with-java-for-dummies.txt
35
+ └── supertwitter
36
+ ├── .twitchrc.yml
37
+ ├── README.md
38
+ └── beginning-programming-with-java-for-dummies.txt
39
+
40
+ 5 directories, 9 files
41
+
42
+ $ head examples/twitch/bin/twitch
43
+ #!/usr/bin/env ruby
44
+
45
+ #
46
+ # Tweet validator
47
+ #
48
+
49
+ require 'rubygems'
50
+ require 'dotsmack'
51
+ require 'yaml'
52
+
53
+ $ examples/twitch/bin/twitch examples/twitch/test/
54
+ examples/twitch/test/a-tale-of-two-cities.txt: 614
55
+
56
+ $ examples/twitch/bin/twitch < examples/twitch/test/a-tale-of-two-cities.txt
57
+ -: 614
58
+ ```
59
+
60
+ More examples:
61
+
62
+ * [aspelllint](https://github.com/mcandre/aspelllint)
63
+ * [enlint](https://github.com/mcandre/enlint)
64
+ * [cowl](https://github.com/mcandre/cowl)
65
+ * [gtdlint](https://github.com/mcandre/gtdlint)
66
+ * [lili](https://github.com/mcandre/lili)
67
+
68
+ # REQUIREMENTS
69
+
70
+ * [Ruby](https://www.ruby-lang.org/) 2+
71
+
72
+ # INSTALL
73
+
74
+ Install via [RubyGems](http://rubygems.org/):
75
+
76
+ ```
77
+ $ gem install aspelllint
78
+ ```
79
+
80
+ # LICENSE
81
+
82
+ FreeBSD
83
+
84
+ # DEVELOPMENT
85
+
86
+ ## Testing
87
+
88
+ Keep the interface working:
89
+
90
+ ```
91
+ $ cucumber
92
+ ```
93
+
94
+ ## Linting
95
+
96
+ Keep the code tidy:
97
+
98
+ ```
99
+ $ rake lint
100
+ ```
101
+
102
+ ## Git Hooks
103
+
104
+ See `hooks/`.
@@ -0,0 +1,241 @@
1
+ require 'rubygems'
2
+ require 'find'
3
+
4
+ #
5
+ # Dotsmack - File, dotignore, and dotconfig scanner.
6
+ #
7
+ # Scans for files recursively.
8
+ #
9
+ # Searches for dotfiles in:
10
+ #
11
+ # * The same directory as path
12
+ # * An ancestor directory, up to $HOME
13
+ # * If path is not $HOME-relative, search only $HOME
14
+ #
15
+ # dotignore assumes fnmatch format.
16
+ # dotconfig may be in any format.
17
+ #
18
+ module Dotsmack
19
+ HOME = File.expand_path(ENV['HOME'])
20
+ PARENT_OF_HOME = File.expand_path('..', HOME)
21
+
22
+ FNMATCH_FLAGS =
23
+ File::FNM_DOTMATCH | # Allow matching on Unix hidden dotfiles
24
+ File::FNM_EXTGLOB # Allow matching with {..., ...} group patterns
25
+
26
+ #
27
+ # More intuitive behavior for fnmatch
28
+ #
29
+ def self.fnmatch?(pattern, path)
30
+ File.fnmatch(pattern, path, FNMATCH_FLAGS) ||
31
+ File.fnmatch("**/#{pattern}", path, FNMATCH_FLAGS) ||
32
+ ((pattern.end_with?('/') || pattern.end_with?('\\')) &&
33
+ File.fnmatch("**/#{pattern}*", path, FNMATCH_FLAGS))
34
+ end
35
+
36
+ #
37
+ # Smacker dotfile scanner/enumerator.
38
+ #
39
+ class Smacker
40
+ attr_accessor :dotignore, :dotconfig, :additional_ignores, :path2ignore, :path2config
41
+
42
+ #
43
+ # Create a Smacker dotfile scanner/enumerator.
44
+ #
45
+ # @dotignore Filename for ignore patterns (optional)
46
+ # @dotconfig Filename for configuration (optional)
47
+ #
48
+ def initialize(dotignore = nil, additional_ignores = [], dotconfig = nil)
49
+ @dotignore = dotignore
50
+ @dotconfig = dotconfig
51
+ @additional_ignores = additional_ignores
52
+
53
+ @path2dotignore = {}
54
+ @path2dotconfig = {}
55
+
56
+ if !dotignore.nil?
57
+ home_dotignore = "#{HOME}#{File::SEPARATOR}#{dotignore}"
58
+
59
+ @path2dotignore[PARENT_OF_HOME] = []
60
+
61
+ @path2dotignore[HOME] =
62
+ if File.exist?(home_dotignore)
63
+ open(home_dotignore).read.split("\n")
64
+ else
65
+ []
66
+ end
67
+ end
68
+
69
+ if !dotconfig.nil?
70
+ home_dotconfig = "#{HOME}#{File::SEPARATOR}#{dotconfig}"
71
+
72
+ @path2dotconfig[PARENT_OF_HOME] = nil
73
+
74
+ @path2dotconfig[HOME] =
75
+ if File.exist?(home_dotconfig)
76
+ open(home_dotconfig).read
77
+ else
78
+ nil
79
+ end
80
+ end
81
+ end
82
+
83
+ #
84
+ # Scan for dotignore.
85
+ #
86
+ # Assumes dir is an absolute path.
87
+ # Assumes dir is not a symlink.
88
+ # Assumes dir is $HOME-relative.
89
+ #
90
+ def scan_for_dotignore!(dir)
91
+ if @path2dotignore.has_key?(dir)
92
+ @path2dotignore[dir]
93
+ else
94
+ candidate = "#{dir}#{File::SEPARATOR}#{@dotignore}"
95
+
96
+ dotignore =
97
+ if File.exist?(candidate)
98
+ open(candidate).read.split("\n")
99
+ else
100
+ []
101
+ end
102
+
103
+ parent = File.expand_path('..', dir)
104
+
105
+ # Determine parent dotignore
106
+ parents_dotignore = scan_for_dotignore!(parent)
107
+
108
+ # Merge candidate and parent information
109
+ dotignore.concat(parents_dotignore)
110
+
111
+ @path2dotignore[dir] = dotignore
112
+
113
+ dotignore
114
+ end
115
+ end
116
+
117
+ #
118
+ # Scan for dotconfig.
119
+ #
120
+ # Assumes dir is an absolute path.
121
+ # Assumes dir is not a symlink.
122
+ # Assumes dir is $HOME-relative.
123
+ #
124
+ def scan_for_dotconfig!(dir)
125
+ if @path2dotconfig.has_key?(dir)
126
+ @path2dotconfig[dir]
127
+ else
128
+ candidate = "#{dir}#{File::SEPARATOR}#{@dotconfig}"
129
+
130
+ parent = File.expand_path('..', dir)
131
+
132
+ # Use first dotconfig found.
133
+ dotconfig =
134
+ if File.exist?(candidate)
135
+ open(candidate).read
136
+ else
137
+ scan_for_dotconfig!(parent)
138
+ end
139
+
140
+ @path2dotconfig[dir] = dotconfig
141
+
142
+ dotconfig
143
+ end
144
+ end
145
+
146
+ #
147
+ # Determines whether path is dotignored.
148
+ #
149
+ def ignore?(path)
150
+ path = File.absolute_path(path)
151
+
152
+ dir =
153
+ if File.directory?(path)
154
+ path
155
+ else
156
+ File.expand_path('..', path)
157
+ end
158
+
159
+ relative_to_home = dir.start_with?(HOME)
160
+
161
+ if !relative_to_home
162
+ dir = HOME
163
+ end
164
+
165
+ scan_for_dotignore!(dir)
166
+
167
+ (@path2dotignore[dir] + @additional_ignores).any? do |pattern|
168
+ Dotsmack::fnmatch?(pattern, path)
169
+ end
170
+ end
171
+
172
+ #
173
+ # Returns dotconfig for path.
174
+ #
175
+ def config(path)
176
+ path = File.absolute_path(path)
177
+
178
+ dir =
179
+ if File.directory?(path)
180
+ path
181
+ else
182
+ File.expand_path('..', path)
183
+ end
184
+
185
+ relative_to_home = dir.start_with?(HOME)
186
+
187
+ if !relative_to_home
188
+ dir = HOME
189
+ end
190
+
191
+ scan_for_dotconfig!(dir)
192
+
193
+ @path2dotconfig[dir]
194
+ end
195
+
196
+ #
197
+ # Recursively enumerate files named or nested in paths array.
198
+ #
199
+ # Skips dotignored files.
200
+ #
201
+ # Returns [file, dotconfig] pairs.
202
+ #
203
+ def enumerate(paths)
204
+ files = []
205
+
206
+ paths.each do |path|
207
+ # STDIN idiom
208
+ if path == '-'
209
+ files << [
210
+ path,
211
+ if @dotconfig.nil?
212
+ nil
213
+ else
214
+ config(Dir.pwd)
215
+ end
216
+ ]
217
+ # Skip symlinks
218
+ elsif File.symlink?(path)
219
+ nil
220
+ elsif File.directory?(path) && (@dotignore.nil? || !ignore?(path))
221
+ files.concat(
222
+ enumerate(
223
+ Find.find(path).reject do |p| File.directory?(p) end
224
+ )
225
+ )
226
+ elsif !ignore?(path)
227
+ files << [
228
+ path,
229
+ if @dotconfig.nil?
230
+ nil
231
+ else
232
+ config(path)
233
+ end
234
+ ]
235
+ end
236
+ end
237
+
238
+ files
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,6 @@
1
+ #
2
+ # Dotsmack
3
+ #
4
+ module Dotsmack
5
+ VERSION = '0.1'
6
+ end
metadata ADDED
@@ -0,0 +1,257 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotsmack
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Pennebaker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ptools
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: reek
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: flay
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: flog
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '4.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '4.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: roodi
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '4.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '4.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: churn
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: cane
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '2.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: '2.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: excellent
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '2.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: '2.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: '0.24'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: '0.24'
153
+ - !ruby/object:Gem::Dependency
154
+ name: tailor
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: '1.4'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: '1.4'
167
+ - !ruby/object:Gem::Dependency
168
+ name: guard
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: '2.6'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ~>
179
+ - !ruby/object:Gem::Version
180
+ version: '2.6'
181
+ - !ruby/object:Gem::Dependency
182
+ name: guard-shell
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ~>
186
+ - !ruby/object:Gem::Version
187
+ version: '0.6'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ~>
193
+ - !ruby/object:Gem::Version
194
+ version: '0.6'
195
+ - !ruby/object:Gem::Dependency
196
+ name: rspec
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ~>
200
+ - !ruby/object:Gem::Version
201
+ version: '3.0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ~>
207
+ - !ruby/object:Gem::Version
208
+ version: '3.0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: cucumber
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ~>
214
+ - !ruby/object:Gem::Version
215
+ version: '1.3'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ~>
221
+ - !ruby/object:Gem::Version
222
+ version: '1.3'
223
+ description: See README.md for example usage
224
+ email: andrew.pennebaker@gmail.com
225
+ executables: []
226
+ extensions: []
227
+ extra_rdoc_files: []
228
+ files:
229
+ - LICENSE.md
230
+ - README.md
231
+ - lib/dotsmack.rb
232
+ - lib/version.rb
233
+ homepage: https://github.com/mcandre/dotsmack
234
+ licenses:
235
+ - FreeBSD
236
+ metadata: {}
237
+ post_install_message:
238
+ rdoc_options: []
239
+ require_paths:
240
+ - lib
241
+ required_ruby_version: !ruby/object:Gem::Requirement
242
+ requirements:
243
+ - - '>='
244
+ - !ruby/object:Gem::Version
245
+ version: '0'
246
+ required_rubygems_version: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - '>='
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ requirements: []
252
+ rubyforge_project:
253
+ rubygems_version: 2.2.2
254
+ signing_key:
255
+ specification_version: 4
256
+ summary: a library for modern, per-directory dotfile configuration
257
+ test_files: []