spotlight 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|