spotlight 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +10 -1
- data/ext/md_item_native/md_item_native.c +101 -16
- data/ext/md_item_native/md_item_native.h +2 -0
- data/lib/spotlight/query.rb +10 -0
- data/spec/md_item_native_spec.rb +16 -5
- data/spec/spec_helper.rb +5 -1
- data/spec/spotlight_query_spec.rb +6 -0
- metadata +13 -3
data/README.rdoc
CHANGED
@@ -9,15 +9,24 @@ Description goes here.
|
|
9
9
|
=== Finds files matching a given query
|
10
10
|
|
11
11
|
query = Spotlight::Query.new('kMDItemKind = "JPEG image" && kMDItemPixelHeight > 2000')
|
12
|
+
query.scopes << '/Users/youpy/'
|
12
13
|
query.execute.map {|item|
|
13
14
|
puts item.get(:kMDItemPath)
|
14
15
|
}
|
15
16
|
|
16
|
-
===
|
17
|
+
=== Creates query from .savedSearch
|
18
|
+
|
19
|
+
query = Spotlight::Query.from_saved_search('foo.savedSearch')
|
20
|
+
|
21
|
+
=== Gets the metadata attribute for the specified file
|
17
22
|
|
18
23
|
item = Spotlight::Item.new('/Users/youpy/foo')
|
19
24
|
item.get(:kMDItemKind)
|
20
25
|
|
26
|
+
=== Gets the metadata attribute names for the specified file
|
27
|
+
|
28
|
+
item.attribute_names
|
29
|
+
|
21
30
|
== Note on Patches/Pull Requests
|
22
31
|
|
23
32
|
* Fork the project.
|
@@ -9,7 +9,73 @@ struct ItemObject {
|
|
9
9
|
CFStringRef CString2CFString(char *str) {
|
10
10
|
return CFStringCreateWithCString(kCFAllocatorDefault,
|
11
11
|
str,
|
12
|
-
|
12
|
+
kCFStringEncodingUTF8);
|
13
|
+
}
|
14
|
+
|
15
|
+
VALUE CFString2RString(CFStringRef str) {
|
16
|
+
int stringSize;
|
17
|
+
char *tmpptr;
|
18
|
+
VALUE result;
|
19
|
+
|
20
|
+
stringSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
|
21
|
+
tmpptr = (char *)malloc(sizeof(char) * stringSize);
|
22
|
+
CFStringGetCString(str, tmpptr, stringSize, kCFStringEncodingUTF8);
|
23
|
+
result = rb_str_new2(tmpptr);
|
24
|
+
free(tmpptr);
|
25
|
+
|
26
|
+
return result;
|
27
|
+
}
|
28
|
+
|
29
|
+
VALUE CFType2Value(CFTypeRef thing) {
|
30
|
+
int i;
|
31
|
+
double doubleValue;
|
32
|
+
CFNumberType numberType;
|
33
|
+
CFAbsoluteTime timeNow;
|
34
|
+
CFGregorianDate current;
|
35
|
+
VALUE result;
|
36
|
+
|
37
|
+
/* CFStringRef stringValue = CFCopyDescription(thing); */
|
38
|
+
/* rb_p(CFString2RString(stringValue)); */
|
39
|
+
/* CFRelease(stringValue); */
|
40
|
+
|
41
|
+
if(CFGetTypeID(thing) == CFStringGetTypeID()) {
|
42
|
+
result = CFString2RString((CFStringRef)thing);
|
43
|
+
} else if(CFGetTypeID(thing) == CFNumberGetTypeID()) {
|
44
|
+
numberType = CFNumberGetType((CFNumberRef)thing);
|
45
|
+
switch(numberType) {
|
46
|
+
case kCFNumberFloat64Type:
|
47
|
+
CFNumberGetValue((CFNumberRef)thing, numberType, &doubleValue);
|
48
|
+
result = rb_float_new(doubleValue);
|
49
|
+
break;
|
50
|
+
case kCFNumberSInt32Type:
|
51
|
+
case kCFNumberSInt64Type:
|
52
|
+
default:
|
53
|
+
CFNumberGetValue((CFNumberRef)thing, kCFNumberDoubleType, &doubleValue);
|
54
|
+
result = INT2FIX((double)doubleValue);
|
55
|
+
break;
|
56
|
+
}
|
57
|
+
} else if(CFGetTypeID(thing) == CFDateGetTypeID()) {
|
58
|
+
timeNow = CFDateGetAbsoluteTime((CFDateRef)thing);
|
59
|
+
current = CFAbsoluteTimeGetGregorianDate(timeNow, NULL);
|
60
|
+
result = rb_funcall(rb_cTime, rb_intern("gm"), 6,
|
61
|
+
INT2FIX((unsigned int)current.year),
|
62
|
+
INT2FIX((unsigned int)current.month),
|
63
|
+
INT2FIX((unsigned int)current.day),
|
64
|
+
INT2FIX((unsigned int)current.hour),
|
65
|
+
INT2FIX((unsigned int)current.minute),
|
66
|
+
INT2FIX((unsigned int)current.second));
|
67
|
+
} else if(CFGetTypeID(thing) == CFBooleanGetTypeID()) {
|
68
|
+
result = CFBooleanGetValue(thing) ? Qtrue : Qfalse;
|
69
|
+
} else if(CFGetTypeID(thing) == CFArrayGetTypeID()) {
|
70
|
+
result = rb_ary_new();
|
71
|
+
for(i = 0; i < CFArrayGetCount(thing); i ++) {
|
72
|
+
rb_ary_push(result, CFType2Value(CFArrayGetValueAtIndex(thing, i)));
|
73
|
+
}
|
74
|
+
} else {
|
75
|
+
result = Qnil;
|
76
|
+
}
|
77
|
+
|
78
|
+
return result;
|
13
79
|
}
|
14
80
|
|
15
81
|
MDItemRef getItem(VALUE obj) {
|
@@ -27,6 +93,7 @@ void cMDItemNative_free(void *ptr) {
|
|
27
93
|
}
|
28
94
|
|
29
95
|
free(ptr);
|
96
|
+
|
30
97
|
/* printf("cMDItemNative_free()\n"); */
|
31
98
|
}
|
32
99
|
|
@@ -53,7 +120,7 @@ static VALUE cMDItemNative_new(int argc, VALUE *argv, VALUE klass)
|
|
53
120
|
if(item != NULL) {
|
54
121
|
obj = createInstanceFromMDItem(item);
|
55
122
|
} else {
|
56
|
-
rb_raise(rb_eArgError, "no such file or directory");
|
123
|
+
rb_raise(rb_eArgError, "no such file or directory: %s", filename);
|
57
124
|
}
|
58
125
|
|
59
126
|
CFRelease(cfFilename);
|
@@ -64,11 +131,10 @@ static VALUE cMDItemNative_new(int argc, VALUE *argv, VALUE klass)
|
|
64
131
|
static VALUE cMDItemNative_get(int argc, VALUE *argv, VALUE self)
|
65
132
|
{
|
66
133
|
MDItemRef item = getItem(self);
|
67
|
-
|
134
|
+
CFTypeRef itemValue;
|
135
|
+
CFStringRef cfAttrName;
|
68
136
|
VALUE attrName, result;
|
69
|
-
|
70
|
-
int stringSize;
|
71
|
-
|
137
|
+
|
72
138
|
rb_scan_args(argc, argv, "1", &attrName);
|
73
139
|
|
74
140
|
if(TYPE(attrName) == T_SYMBOL) {
|
@@ -77,23 +143,41 @@ static VALUE cMDItemNative_get(int argc, VALUE *argv, VALUE self)
|
|
77
143
|
cfAttrName = (CFStringRef)CString2CFString(StringValuePtr(attrName));
|
78
144
|
}
|
79
145
|
|
80
|
-
|
146
|
+
/* rb_p(CFString2RString(cfAttrName)); */
|
147
|
+
|
148
|
+
itemValue = MDItemCopyAttribute(item, cfAttrName);
|
149
|
+
|
150
|
+
CFRelease(cfAttrName);
|
81
151
|
|
82
152
|
if(itemValue != NULL) {
|
83
|
-
|
84
|
-
|
153
|
+
result = CFType2Value(itemValue);
|
154
|
+
CFRelease(itemValue);
|
155
|
+
return result;
|
156
|
+
}
|
85
157
|
|
86
|
-
|
158
|
+
return Qnil;
|
159
|
+
}
|
87
160
|
|
88
|
-
|
161
|
+
static VALUE cMDItemNative_attribute_names(int argc, VALUE *argv, VALUE self)
|
162
|
+
{
|
163
|
+
MDItemRef item = getItem(self);
|
164
|
+
CFArrayRef cfAttributeNames;
|
165
|
+
VALUE result = rb_ary_new();
|
166
|
+
int numAttributes, i;
|
89
167
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
168
|
+
rb_scan_args(argc, argv, "0");
|
169
|
+
|
170
|
+
cfAttributeNames = MDItemCopyAttributeNames(item);
|
171
|
+
|
172
|
+
if(cfAttributeNames != NULL) {
|
173
|
+
numAttributes = (int)CFArrayGetCount(cfAttributeNames);
|
174
|
+
for(i = 0; i < numAttributes; i ++) {
|
175
|
+
rb_ary_push(result, CFString2RString((CFStringRef)CFArrayGetValueAtIndex(cfAttributeNames, i)));
|
176
|
+
}
|
95
177
|
}
|
96
178
|
|
179
|
+
CFRelease(cfAttributeNames);
|
180
|
+
|
97
181
|
return result;
|
98
182
|
}
|
99
183
|
|
@@ -104,4 +188,5 @@ void Init_md_item_native(void){
|
|
104
188
|
rb_cMDItemNative = rb_define_class_under(rb_mSpotlight, "MDItemNative", rb_cObject);
|
105
189
|
rb_define_singleton_method(rb_cMDItemNative, "new", cMDItemNative_new, -1);
|
106
190
|
rb_define_method(rb_cMDItemNative, "get", cMDItemNative_get, -1);
|
191
|
+
rb_define_method(rb_cMDItemNative, "attribute_names", cMDItemNative_attribute_names, -1);
|
107
192
|
}
|
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
#include <ruby.h>
|
5
5
|
#include </System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Headers/MDItem.h>
|
6
|
+
#include </System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFDate.h>
|
7
|
+
#include </System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFNumber.h>
|
6
8
|
|
7
9
|
VALUE createInstanceFromMDItem(MDItemRef item);
|
8
10
|
|
data/lib/spotlight/query.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'plist'
|
3
|
+
|
1
4
|
module Spotlight
|
2
5
|
class Query
|
3
6
|
attr_reader :query_string
|
4
7
|
attr_accessor :scopes
|
5
8
|
|
9
|
+
def self.from_saved_search(filename)
|
10
|
+
plist = Plist::parse_xml(filename)
|
11
|
+
query = new(plist['RawQuery'])
|
12
|
+
query.scopes = plist['SearchCriteria']['FXScopeArrayOfPaths']
|
13
|
+
query
|
14
|
+
end
|
15
|
+
|
6
16
|
def initialize(query_string)
|
7
17
|
@query_string = query_string
|
8
18
|
@scopes = []
|
data/spec/md_item_native_spec.rb
CHANGED
@@ -2,19 +2,30 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe Spotlight::MDItemNative do
|
4
4
|
before do
|
5
|
-
@
|
5
|
+
@item = Spotlight::MDItemNative.new(__FILE__)
|
6
|
+
@filename = File.basename(__FILE__)
|
6
7
|
end
|
7
8
|
|
8
9
|
it "should instanciate" do
|
9
|
-
@
|
10
|
+
@item.should be_an_instance_of(Spotlight::MDItemNative)
|
10
11
|
end
|
11
12
|
|
12
13
|
it "should get attribute by name" do
|
13
|
-
@
|
14
|
-
@
|
14
|
+
@item.get('kMDItemKind').should eql('Ruby Source File')
|
15
|
+
@item.get(:kMDItemKind).should eql('Ruby Source File')
|
16
|
+
@item.get(:kMDItemFSName).should eql(@filename)
|
17
|
+
@item.get(:kMDItemFSCreationDate).should be_an_instance_of(Time)
|
18
|
+
@item.get(:kMDItemFSOwnerUserID).should be_an_instance_of(Fixnum)
|
19
|
+
@item.get(:kMDItemFSIsExtensionHidden).should be_an_instance_of(FalseClass)
|
15
20
|
end
|
16
21
|
|
17
22
|
it "should get nil if attribute is not found" do
|
18
|
-
@
|
23
|
+
@item.get('kMDXXXXXX').should be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should get attribute names" do
|
27
|
+
attribute_names = @item.attribute_names
|
28
|
+
attribute_names.should be_an_instance_of(Array)
|
29
|
+
attribute_names.should be_include('kMDItemKind')
|
19
30
|
end
|
20
31
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,6 +5,12 @@ describe Spotlight::Query do
|
|
5
5
|
@query = Spotlight::Query.new('kMDItemDisplayName = "spotlight_query_spec.rb"')
|
6
6
|
end
|
7
7
|
|
8
|
+
it "should create query from saved search" do
|
9
|
+
query = Spotlight::Query.from_saved_search(fixture('test.savedSearch'))
|
10
|
+
query.query_string.should eql('((true) && (true)) && ((* = "test*"cdw || kMDItemTextContent = "test*"cdw))')
|
11
|
+
query.scopes.should eql(['kMDQueryScopeComputer'])
|
12
|
+
end
|
13
|
+
|
8
14
|
it "should have query string" do
|
9
15
|
@query.query_string.should eql('kMDItemDisplayName = "spotlight_query_spec.rb"')
|
10
16
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotlight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- youpy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-18 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,6 +32,16 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: "0"
|
34
34
|
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: plist
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
35
45
|
description: Library to use Spotlight from Ruby
|
36
46
|
email: youpy@buycheapviagraonlinenow.com
|
37
47
|
executables: []
|
@@ -51,7 +61,7 @@ files:
|
|
51
61
|
- LICENSE
|
52
62
|
- README.rdoc
|
53
63
|
has_rdoc: true
|
54
|
-
homepage: http://github.com/youpy/spotlight
|
64
|
+
homepage: http://github.com/youpy/ruby-spotlight
|
55
65
|
licenses: []
|
56
66
|
|
57
67
|
post_install_message:
|