extattr 0.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/gemstub.rb ADDED
@@ -0,0 +1,22 @@
1
+ unless version = File.read("README.md").scan(/^\s*[\*\-]\s*version:{1,2}\s*(.+)/i).flatten[-1]
2
+ raise "バージョン情報が README.md に見つかりません"
3
+ end
4
+
5
+ DOC << "QUICKREF.ja.md"
6
+
7
+ GEMSTUB = Gem::Specification.new do |s|
8
+ s.name = "extattr"
9
+ s.version = version
10
+ s.summary = "extended file attribute manipurator"
11
+ s.description = <<-EOS
12
+ "extattr" is extended file attribute manipurator for Ruby.
13
+ Supported for FreeBSD (extattr), GNU/Linux (xattr) and Microsoft Windows (NTFS Alternative Data Stream (ADS) + NTFS Extended Attributes (EA)).
14
+ EOS
15
+ s.homepage = "https://github.com/dearblue/ruby-extattr"
16
+ s.license = "BSD-2-Clause"
17
+ s.author = "dearblue"
18
+ s.email = "dearblue@users.osdn.me"
19
+
20
+ s.add_development_dependency "rake", "~> 0"
21
+ s.add_development_dependency "test-unit", "~> 0"
22
+ end
data/lib/extattr.rb CHANGED
@@ -1,57 +1,274 @@
1
- #vim: set fileencoding:utf-8
1
+ #!ruby
2
2
 
3
- ver = RbConfig::CONFIG["ruby_version"]
3
+ ver = RUBY_VERSION.slice(/\d+\.\d+/)
4
4
  soname = File.basename(__FILE__, ".rb") << ".so"
5
- lib = File.join(File.dirname(__FILE__), ver, soname)
6
- if File.file?(lib)
7
- require_relative File.join(ver, soname)
8
- else
9
- require_relative soname
5
+ lib = File.join(ver, soname)
6
+ begin
7
+ require_relative lib
8
+ rescue LoadError
9
+ require lib
10
10
  end
11
11
 
12
12
  #
13
- # Add operation methods of extended file attribute to File.
13
+ # Add operation methods of filesystem extended attributes to File.
14
14
  #
15
- # File クラスに拡張属性を操作するメソッドを追加します。
15
+ # === 名前空間の指定について
16
16
  #
17
- # 感嘆符 (『!』) のついたメソッドは、シンボリックリンクに対する操作となります。
17
+ # 拡張属性の名前空間を指定する場合、以下の値が利用できます:
18
18
  #
19
- # メソッドにキーワード引数として <code>namespace:</code> を与えることにより、拡張属性の名前空間を指定することが出来ます。
19
+ # * ExtAttr::USER, ExtAttr::SYSTEM
20
+ # * 文字列又はシンボルで +user+、+system+ (大文字小文字を区別しません)
20
21
  #
21
- # 現在の実装においては <code>EXTATTR_NAMESPACE_USER</code> と <code>EXTATTR_NAMESPACE_SYSTEM</code> のみが利用可能です。
22
+ # これらの値は内部で変換、または処理が分岐されます。
22
23
  #
23
- class File
24
+ # extattr::
25
+ # 整数値に変換されて処理されます。
26
+ #
27
+ # xattr::
28
+ # 拡張属性名に "user." または "system." を追加して処理されます。
29
+ #
30
+ # Windows::
31
+ # ExtAttr::USER の場合は NTFS Alternative Data Stream (ADS) として処理されます。
32
+ #
33
+ # ExtAttr::SYSTEM の場合は NTFS Extended Attribute (EA) として処理されます。
34
+ #
35
+ module ExtAttr
36
+ ExtAttr = self
37
+
38
+ def self.open(path)
39
+ if path.kind_of?(File)
40
+ ea = ExtAttr::Accessor[path, path.to_path]
41
+ block_given? ? yield(ea) : ea
42
+ else
43
+ if block_given?
44
+ ::File.open(path) do |file|
45
+ return yield(ExtAttr::Accessor[file, path])
46
+ end
47
+ else
48
+ ExtAttr::Accessor[::File.open(path), path]
49
+ end
50
+ end
51
+ end
52
+
24
53
  #
25
54
  # call-seq:
26
- # extattr_each(path, namespace: File::EXTATTR_NAMESPACE_USER) -> Enumerator
27
- # extattr_each(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name, data| ... } -> File
28
- # extattr_each!(path, namespace: File::EXTATTR_NAMESPACE_USER) -> Enumerator
29
- # extattr_each!(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name, data| ... } -> File
55
+ # each(path, namespace = ExtAttr::USER) -> Enumerator
56
+ # each(path, namespace = ExtAttr::USER) { |name| ... } -> path
30
57
  #
31
- def self.extattr_each(path, *namespace)
32
- return to_enum(:extattr_each, path, *namespace) unless block_given?
58
+ def self.each(path, namespace = ExtAttr::USER, &block)
59
+ return to_enum(:each, path, namespace) unless block
60
+
61
+ list(path, namespace, &block)
33
62
 
34
- extattr_list(path, *namespace) do |name|
35
- yield(name, extattr_get(path, name, *namespace))
36
- end
37
63
  self
38
64
  end
39
65
 
40
- def self.extattr_each!(path, *namespace)
41
- return to_enum(:extattr_each!, path, *namespace) unless block_given?
66
+ #
67
+ # call-seq:
68
+ # each!(path, namespace = ExtAttr::USER) -> Enumerator
69
+ # each!(path, namespace = ExtAttr::USER) { |name| ... } -> path
70
+ #
71
+ def self.each!(path, namespace = ExtAttr::USER, &block)
72
+ return to_enum(:each!, path, namespace) unless block
73
+
74
+ list!(path, namespace, &block)
42
75
 
43
- extattr_list!(path, *namespace) do |name|
44
- yield(name, extattr_get!(path, name, *namespace))
45
- end
46
76
  self
47
77
  end
48
78
 
49
- def extattr_each(*namespace)
50
- return to_enum(:extattr_each, *namespace) unless block_given?
79
+ #
80
+ # call-seq:
81
+ # each_pair(path, namespace = ExtAttr::USER) -> Enumerator
82
+ # each_pair(path, namespace = ExtAttr::USER) { |name, data| ... } -> path
83
+ #
84
+ def self.each_pair(path, namespace = ExtAttr::USER, &block)
85
+ return to_enum(:each_pair, path, namespace) unless block
86
+
87
+ list(path, namespace) { |name| yield(name, get(path, namespace, name)) }
88
+
89
+ self
90
+ end
91
+
92
+ #
93
+ # call-seq:
94
+ # each_pair!(path, namespace = ExtAttr::USER) -> Enumerator
95
+ # each_pair!(path, namespace = ExtAttr::USER) { |name, data| ... } -> path
96
+ #
97
+ def self.each_pair!(path, namespace = ExtAttr::USER, &block)
98
+ return to_enum(:each_pair!, path, namespace) unless block
99
+
100
+ list!(path, namespace) { |name| yield(name, get!(path, namespace, name)) }
51
101
 
52
- extattr_list(*namespace) do |name|
53
- yield(name, extattr_get(name, *namespace))
54
- end
55
102
  self
56
103
  end
104
+
105
+ class Accessor < Struct.new(:obj, :path)
106
+ BasicStruct = superclass
107
+ VIRT_ENOATTR = (ExtAttr::IMPLEMENT == "windows" ? Errno::ENOENT : Errno::ENOATTR)
108
+
109
+ def [](name, namespace = ExtAttr::USER)
110
+ begin
111
+ ExtAttr.get(obj, namespace, name)
112
+ rescue VIRT_ENOATTR
113
+ nil
114
+ end
115
+ end
116
+
117
+ def []=(name, namespace = ExtAttr::USER, data)
118
+ if data.nil?
119
+ ExtAttr.delete(obj, namespace, name)
120
+ else
121
+ ExtAttr.set(obj, namespace, name, data)
122
+ end
123
+ end
124
+
125
+ def each(namespace: ExtAttr::USER, &block)
126
+ ExtAttr.each(obj, namespace, &block)
127
+ end
128
+
129
+ def each_pair(namespace: ExtAttr::USER, &block)
130
+ ExtAttr.each_pair(obj, namespace, &block)
131
+ end
132
+
133
+ def list(namespace: ExtAttr::USER, &block)
134
+ ExtAttr.list(obj, namespace, &block)
135
+ end
136
+
137
+ def size(name, namespace: ExtAttr::USER)
138
+ ExtAttr.size(obj, namespace, name)
139
+ end
140
+
141
+ def get(name, namespace: ExtAttr::USER)
142
+ ExtAttr.get(obj, namespace, name)
143
+ end
144
+
145
+ def set(name, data, namespace: ExtAttr::USER)
146
+ ExtAttr.set(obj, namespace, name, data)
147
+ end
148
+
149
+ def delete(name, namespace: ExtAttr::USER)
150
+ ExtAttr.delete(obj, namespace, name)
151
+ end
152
+ end
153
+
154
+ refine File do
155
+ def extattr
156
+ ExtAttr::Accessor[self, to_path]
157
+ end
158
+
159
+ #
160
+ # Enumeration file extattr.
161
+ #
162
+ def extattr_each(namespace: ExtAttr::USER, &block)
163
+ ExtAttr.each(self, namespace, &block)
164
+ end
165
+
166
+ #
167
+ # Enumeration file extattr.
168
+ #
169
+ def extattr_each_pair(namespace: ExtAttr::USER, &block)
170
+ ExtAttr.each_pair(self, namespace, &block)
171
+ end
172
+
173
+ #
174
+ # call-seq:
175
+ # extattr_list(namespace: ExtAttr::USER) -> array of strings
176
+ # extattr_list(namespace: ExtAttr::USER) { |name| ... } -> enumerator
177
+ #
178
+ # Get file extattr list.
179
+ #
180
+ def extattr_list(namespace: ExtAttr::USER, &block)
181
+ ExtAttr.list(self, namespace, &block)
182
+ end
183
+
184
+ #
185
+ # Get file extattr data size.
186
+ #
187
+ def extattr_size(name, namespace: ExtAttr::USER)
188
+ ExtAttr.size(self, namespace, name)
189
+ end
190
+
191
+ #
192
+ # Get file extattr data.
193
+ #
194
+ def extattr_get(name, namespace: ExtAttr::USER)
195
+ ExtAttr.get(self, namespace, name)
196
+ end
197
+
198
+ #
199
+ # Set file extattr data.
200
+ #
201
+ def extattr_set(name, value, namespace: ExtAttr::USER)
202
+ ExtAttr.set(self, namespace, name, value)
203
+ end
204
+
205
+ #
206
+ # Delete file extattr.
207
+ #
208
+ def extattr_delete(name, namespace: ExtAttr::USER)
209
+ ExtAttr.delete(self, namespace, name)
210
+ end
211
+ end
212
+
213
+ refine File.singleton_class do
214
+ def extattr(path)
215
+ ExtAttr.open(path)
216
+ end
217
+
218
+ def extattr_each(path, namespace: ExtAttr::USER, &block)
219
+ ExtAttr.each(path, namespace, &block)
220
+ end
221
+
222
+ def extattr_each!(path, namespace: ExtAttr::USER, &block)
223
+ ExtAttr.each!(path, namespace, &block)
224
+ end
225
+
226
+ def extattr_each_pair(path, namespace: ExtAttr::USER, &block)
227
+ ExtAttr.each_pair(path, namespace, &block)
228
+ end
229
+
230
+ def extattr_each_pair!(path, namespace: ExtAttr::USER, &block)
231
+ ExtAttr.each_pair!(path, namespace, &block)
232
+ end
233
+
234
+ def extattr_list(path, namespace: ExtAttr::USER, &block)
235
+ ExtAttr.list(path, namespace, &block)
236
+ end
237
+
238
+ def extattr_list!(path, namespace: ExtAttr::USER, &block)
239
+ ExtAttr.list!(path, namespace, &block)
240
+ end
241
+
242
+ def extattr_get(path, name, namespace: ExtAttr::USER)
243
+ ExtAttr.get(path, namespace, name)
244
+ end
245
+
246
+ def extattr_get!(path, name, namespace: ExtAttr::USER)
247
+ ExtAttr.get(path, namespace, name)
248
+ end
249
+
250
+ def extattr_size(path, name, namespace: ExtAttr::USER)
251
+ ExtAttr.size(path, namespace, name)
252
+ end
253
+
254
+ def extattr_size!(path, name, namespace: ExtAttr::USER)
255
+ ExtAttr.size(path, namespace, name)
256
+ end
257
+
258
+ def extattr_set(path, name, value, namespace: ExtAttr::USER)
259
+ ExtAttr.set(path, namespace, name, value)
260
+ end
261
+
262
+ def extattr_set!(path, name, value, namespace: ExtAttr::USER)
263
+ ExtAttr.set(path, namespace, name, value)
264
+ end
265
+
266
+ def extattr_delete(path, name, namespace: ExtAttr::USER)
267
+ ExtAttr.delete(path, namespace, name)
268
+ end
269
+
270
+ def extattr_delete!(path, name, namespace: ExtAttr::USER)
271
+ ExtAttr.delete(path, namespace, name)
272
+ end
273
+ end
57
274
  end
@@ -0,0 +1,75 @@
1
+ #!ruby
2
+
3
+ require "test/unit"
4
+ require "fileutils"
5
+ require "tmpdir"
6
+
7
+ include FileUtils
8
+
9
+ require "extattr"
10
+
11
+ using ExtAttr
12
+
13
+ class ExtAttr::Test < Test::Unit::TestCase
14
+ WORKDIR = Dir.mktmpdir(["", ".ruby-extattr.test-work"])
15
+ FILEPATH1 = File.join(WORKDIR, "file1")
16
+ FILEPATH2 = File.join(WORKDIR, "file2")
17
+
18
+ def self.startup
19
+ @@file = File.open(FILEPATH1, "a")
20
+ end
21
+
22
+ def self.shutdown
23
+ @@file.close
24
+ @@file = nil
25
+ Dir.chdir "/" rescue nil
26
+ rmtree WORKDIR, secure: true, verbose: true #, noop: true
27
+ end
28
+
29
+ def test_fd_extattr
30
+ extdata = "abcdefg"
31
+
32
+ assert_equal([], @@file.extattr_list)
33
+ assert_nil(@@file.extattr_set("ext1", extdata))
34
+ assert_equal(["ext1"], @@file.extattr_list())
35
+ assert_equal("ext1", `lsextattr -qq user #{@@file.to_path}`.chomp) if RUBY_PLATFORM =~ /freebsd/
36
+ assert_equal(extdata, @@file.extattr_get("ext1"))
37
+ assert_equal(extdata, `getextattr -qq user ext1 #{@@file.to_path}`) if RUBY_PLATFORM =~ /freebsd/
38
+ assert_nil(@@file.extattr_delete("ext1"))
39
+ assert_equal([], @@file.extattr_list())
40
+ end
41
+
42
+ def test_extattr
43
+ extdata = "abcdefg"
44
+ File.open(FILEPATH2, "ab") {}
45
+
46
+ assert_equal([], File.extattr_list(FILEPATH2))
47
+ assert_nil(File.extattr_set(FILEPATH2, "ext1", extdata))
48
+ assert_equal(["ext1"], File.extattr_list(FILEPATH2))
49
+ assert_equal(extdata, File.extattr_get(FILEPATH2, "ext1"))
50
+ assert_nil(File.extattr_delete(FILEPATH2, "ext1"))
51
+ assert_equal([], File.extattr_list(FILEPATH2))
52
+ end
53
+
54
+ def test_ractor_extattr
55
+ # Skip this test on Ruby < 3.0
56
+ return true unless defined?(Ractor)
57
+
58
+ # Ractor is still experimental in Ruby 3.0.x — suppress warning for this test.
59
+ old_warning_status = Warning[:experimental]
60
+ Warning[:experimental] = false
61
+
62
+ extdata = "abcdefg"
63
+ File.open(FILEPATH2, "ab") {}
64
+
65
+ assert_equal([], File.extattr_list(FILEPATH2))
66
+ assert_nil(File.extattr_set(FILEPATH2, "ext1", extdata))
67
+
68
+ assert_equal(["ext1"], Ractor.new(FILEPATH2) { |path| File.extattr_list(path) }.take)
69
+ assert_equal(extdata, Ractor.new(FILEPATH2) { |path| File.extattr_get(path, "ext1") }.take)
70
+
71
+ assert_nil(File.extattr_delete(FILEPATH2, "ext1"))
72
+ assert_equal([], File.extattr_list(FILEPATH2))
73
+ Warning[:experimental] = old_warning_status
74
+ end
75
+ end
metadata CHANGED
@@ -1,53 +1,64 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extattr
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - dearblue
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-16 00:00:00.000000000 Z
11
+ date: 2021-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
14
+ name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.14'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.14'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: test-unit
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  description: |
42
- extattr is extended file attribute operation library for ruby.
43
- Supported for FreeBSD (extattr), GNU/Linux (xattr) and Microsoft Windows (NTFS ADS + Extended Attributes).
44
- email: dearblue@users.sourceforge.jp
42
+ "extattr" is extended file attribute manipurator for Ruby.
43
+ Supported for FreeBSD (extattr), GNU/Linux (xattr) and Microsoft Windows (NTFS Alternative Data Stream (ADS) + NTFS Extended Attributes (EA)).
44
+ email: dearblue@users.osdn.me
45
45
  executables: []
46
46
  extensions:
47
47
  - ext/extconf.rb
48
- extra_rdoc_files: []
48
+ extra_rdoc_files:
49
+ - HISTORY.ja.md
50
+ - LICENSE.md
51
+ - QUICKREF.ja.md
52
+ - README.md
53
+ - ext/extattr-extattr.h
54
+ - ext/extattr-windows.h
55
+ - ext/extattr-xattr.h
56
+ - ext/extattr.c
57
+ - lib/extattr.rb
49
58
  files:
59
+ - HISTORY.ja.md
50
60
  - LICENSE.md
61
+ - QUICKREF.ja.md
51
62
  - README.md
52
63
  - Rakefile
53
64
  - ext/extattr-extattr.h
@@ -55,17 +66,18 @@ files:
55
66
  - ext/extattr-xattr.h
56
67
  - ext/extattr.c
57
68
  - ext/extconf.rb
69
+ - gemstub.rb
58
70
  - lib/extattr.rb
59
- - spec/extattr_spec.rb
60
- homepage: http://sourceforge.jp/projects/rutsubo/
71
+ - test/test_extattr.rb
72
+ homepage: https://github.com/dearblue/ruby-extattr
61
73
  licenses:
62
- - 2-clause BSD License
74
+ - BSD-2-Clause
63
75
  metadata: {}
64
- post_install_message:
76
+ post_install_message:
65
77
  rdoc_options:
66
78
  - "--charset"
67
79
  - UTF-8
68
- - "--main"
80
+ - "-m"
69
81
  - README.md
70
82
  require_paths:
71
83
  - lib
@@ -73,17 +85,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
73
85
  requirements:
74
86
  - - ">="
75
87
  - !ruby/object:Gem::Version
76
- version: 1.9.3
88
+ version: '0'
77
89
  required_rubygems_version: !ruby/object:Gem::Requirement
78
90
  requirements:
79
91
  - - ">="
80
92
  - !ruby/object:Gem::Version
81
93
  version: '0'
82
94
  requirements: []
83
- rubyforge_project:
84
- rubygems_version: 2.2.2
85
- signing_key:
95
+ rubygems_version: 3.2.14
96
+ signing_key:
86
97
  specification_version: 4
87
- summary: extended attribute operation library for ruby
98
+ summary: extended file attribute manipurator
88
99
  test_files: []
89
- has_rdoc:
data/spec/extattr_spec.rb DELETED
@@ -1,62 +0,0 @@
1
- #vim: set fileencoding:utf-8
2
-
3
- require "tmpdir"
4
- basedir = File.join(Dir.tmpdir, "ruby-extattr.test-work")
5
- Dir.mkdir basedir unless File.directory? basedir
6
- filepath = File.join(basedir, "file1")
7
-
8
- require "extattr"
9
-
10
- extdata = "abcdefg"
11
-
12
- Dir.chdir basedir do
13
- describe "file" do
14
- file = nil
15
- before(:all) do
16
- file = File.open(filepath, "a")
17
- end
18
-
19
- it ".extattr_list" do
20
- file.extattr_list.should eq([])
21
- end
22
-
23
- after(:all) do
24
- file.close
25
- file = nil
26
- end
27
- end
28
-
29
- describe File do
30
- before(:all) do
31
- File.open(filepath, "a") {}
32
- end
33
-
34
- it ".extattr_list" do
35
- File.extattr_list(filepath).should eq([])
36
- end
37
-
38
- it ".extattr_set" do
39
- File.extattr_set(filepath, "ext1", extdata).should nil
40
- end
41
-
42
- it ".extattr_list ((2))" do
43
- File.extattr_list(filepath).should eq(["ext1"])
44
- end
45
-
46
- it ".extattr_get" do
47
- File.extattr_get(filepath, "ext1").should eq(extdata)
48
- end
49
-
50
- it ".extattr_delete" do
51
- File.extattr_delete(filepath, "ext1").should nil
52
- end
53
-
54
- it ".extattr_list ((3))" do
55
- File.extattr_list(filepath).should eq([])
56
- end
57
-
58
- after(:all) do
59
- File.unlink filepath
60
- end
61
- end
62
- end