public
Description: DataMapper Adapters
Homepage: http://www.yehudakatz.com
Clone URL: git://github.com/wycats/dm-adapters.git
Search Repo:
Initial release of some sample adapters.
wycats (author)
Fri May 09 15:20:51 -0700 2008
commit  bab2839a0cab36315116aae7ac91fc397ae5ccb6
tree    98c4993a48ee11ad977423b36a1e517ec89987d9
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
0
@@ -0,0 +1,117 @@
0
+require "rubygems"
0
+gem "dm-core"
0
+require "data_mapper"
0
+require "fileutils"
0
+require "digest/sha1"
0
+
0
+module DataMapper
0
+ module Adapters
0
+
0
+ class FileAdapter < AbstractAdapter
0
+
0
+ def read(repository, resource, key)
0
+ properties = resource.properties(repository.name).select { |property| !property.lazy? }
0
+ properties_with_indexes = Hash[*properties.zip((0...properties.size).to_a).flatten]
0
+
0
+ set = Collection.new(repository, resource, properties_with_indexes)
0
+
0
+ begin
0
+ set.load [key, File.read(File.join(key_to_path(key), key))]
0
+ set.first
0
+ rescue
0
+ nil
0
+ end
0
+ end
0
+
0
+ def create(repository, instance)
0
+ update(repository, instance)
0
+ end
0
+
0
+ def update(repository, instance)
0
+ dirty_attributes = instance.dirty_attributes
0
+ properties = instance.class.properties(name).select { |property| dirty_attributes.include?(property) }
0
+
0
+ begin
0
+ FileUtils.mkdir_p key_to_path(instance.key)
0
+ file = File.open(File.join(key_to_path(instance.key), instance.key), "w") do |f|
0
+ text_col = dirty_attributes[properties.find {|x| !x.key?}.name]
0
+ f.print text_col
0
+ f.flush
0
+ end
0
+ true
0
+ rescue
0
+ false
0
+ end
0
+ end
0
+
0
+ def delete(repository, instance)
0
+ begin
0
+ FileUtils.rm(File.join(key_to_path(instance.key), instance.key))
0
+ true
0
+ rescue
0
+ false
0
+ end
0
+ end
0
+
0
+ def read_one(repository, query)
0
+ read_set(repository, query, true)
0
+ end
0
+
0
+ def read_set(repository, query, one = false)
0
+ properties = query.fields
0
+ properties_with_indexes = Hash[*properties.zip((0...properties.size).to_a).flatten]
0
+
0
+ set = Collection.new(repository, query.model, properties_with_indexes)
0
+
0
+ key_cond, text_cond = query.conditions.partition {|kind, prop, cond| prop.key?}
0
+ key_cond.flatten!; text_cond.flatten!
0
+
0
+ filename = case key_cond.first
0
+ when :eql then key_cond.last
0
+ when :like then "*#{key_cond.last}*"
0
+ when nil
0
+ else raise ArgumentError, "You can only use equals or .like on the filename"
0
+ end || "*"
0
+
0
+ contents = case text_cond.first
0
+ when :eql
0
+ /#{text_cond.last}/
0
+ when :like
0
+ /.*#{text_cond.last}.*/
0
+ when nil
0
+ else
0
+ raise ArgumentError, "You can only use equals or .like on the contents"
0
+ end || /.*/
0
+
0
+ contents = Dir["#{@uri.path}/**/#{filename}"].each do |file|
0
+ next unless File.file?(file)
0
+ txt = File.read(file)
0
+ if txt =~ contents
0
+ item = set.load [File.basename(file), txt]
0
+ return item if one
0
+ end
0
+ end
0
+ set.entries
0
+ end
0
+
0
+ private
0
+ def key_to_path(key)
0
+ File.join(@uri.path, Digest::SHA1.hexdigest(key.join('+')).scan(/.{5}/))
0
+ end
0
+
0
+ end
0
+
0
+ end
0
+end
0
+
0
+class Foo
0
+ include DataMapper::Resource
0
+ property :name, String, :key => true
0
+ property :text, String
0
+
0
+ def inspect
0
+ self.class.properties(:default).inject({}) {|s,x| s.merge(x.name => self.instance_variable_get("@#{x.name}"))}.inspect
0
+ end
0
+end
0
+
0
+DataMapper.setup(:default, "file:///Users/wycats/textmate/dm/adapters")
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
0
@@ -0,0 +1,113 @@
0
+require "rubygems"
0
+gem "dm-core"
0
+require "data_mapper"
0
+require "net/imap"
0
+require "#{File.dirname(__FILE__)}/types"
0
+require "#{File.dirname(__FILE__)}/typecast"
0
+
0
+# DataMapper.setup(:default, "imap://wycats%40gmail.com:pass@imap.gmail.com/INBOX")
0
+
0
+module DataMapper
0
+ module Adapters
0
+
0
+ class ImapAdapter < AbstractAdapter
0
+ def connect
0
+ @imap = Net::IMAP.new(@uri.host, 993, true)
0
+ begin
0
+ @imap.send(:send_command, "authenticate", "login")
0
+ rescue
0
+ ensure
0
+ @imap.send(:send_command, "login", URI.unescape(@uri.user), @uri.password)
0
+ end
0
+ @imap.select(@uri.path.gsub(%r{^/}, ""))
0
+ end
0
+
0
+ def read(repository, resource, key)
0
+ properties = resource.properties(name).defaults
0
+ properties_with_indexes = Hash[*properties.zip((0...properties.size).to_a).flatten]
0
+
0
+ set = Collection.new(repository, resource, properties_with_indexes)
0
+
0
+ connect
0
+
0
+ imap_results = @imap.uid_fetch(key, imap_props(properties))
0
+ materialize_imap_results(set, imap_results, properties_with_indexes)
0
+ set.first
0
+ end
0
+
0
+ def read_set(repository, query, one = false)
0
+ properties = query.fields
0
+ properties_with_indexes = Hash[*properties.zip((0...properties.size).to_a).flatten]
0
+
0
+ set = Collection.new(repository, query.model, properties_with_indexes)
0
+
0
+ query_array = query_to_array(query)
0
+ query_array.unshift "ALL"
0
+
0
+ begin
0
+ connect unless @imap
0
+ if one
0
+ imap_results = @imap.fetch(1, imap_props(properties))
0
+ else
0
+ imap_seqs = @imap.search(query_array)
0
+ puts "@imap.fetch(#{imap_seqs.inspect}, #{imap_props(properties).inspect})"
0
+ imap_results = @imap.fetch(imap_seqs, imap_props(properties))
0
+ end
0
+ rescue Net::IMAP::NoResponseError
0
+ connect
0
+ retry
0
+ end
0
+
0
+ materialize_imap_results(set, imap_results, properties_with_indexes, query.reload?)
0
+ set
0
+ end
0
+
0
+ def read_one(repository, query)
0
+ read_set(repository, query, true).first
0
+ end
0
+
0
+ def query_to_array(query)
0
+ result = []
0
+ query.conditions.each do |op, prop, val|
0
+ result += (prop.type.query_details[op] + [typecast_dump(val)])
0
+ end
0
+ result
0
+ end
0
+
0
+ def materialize_imap_results(set, results, properties_with_indexes, reload = false)
0
+ results.each do |result|
0
+ props = properties_with_indexes.inject([]) do |accum, prop_idx|
0
+ prop, idx = prop_idx
0
+ prop_result = result.attr[prop.field.upcase]
0
+ prop_result = prop_result.send(prop.type.envelope_name) if prop.type.envelope?
0
+ accum[idx] = typecast_load(prop_result, prop)
0
+ accum
0
+ end
0
+ set.load props, reload
0
+ end
0
+ end
0
+
0
+ def imap_props(properties)
0
+ properties.map {|prop| prop.field.upcase}.uniq
0
+ end
0
+
0
+ end
0
+
0
+ end
0
+end
0
+
0
+ImapTypes = DataMapper::Adapters::Imap
0
+
0
+class Gmail
0
+ include DataMapper::Resource
0
+
0
+ property :id, ImapTypes::Uid, :key => true
0
+ property :subject, ImapTypes::Subject
0
+ property :sender, ImapTypes::Sender
0
+ property :date, ImapTypes::InternalDate
0
+ property :body, ImapTypes::Body, :lazy => true
0
+
0
+ def inspect
0
+ self.class.properties(:default).inject({}) {|s,x| s.merge(x.name => self.instance_variable_get("@#{x.name}"))}.inspect
0
+ end
0
+end
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
0
@@ -0,0 +1,26 @@
0
+module DataMapper
0
+ module Adapters
0
+
0
+ class ImapAdapter < AbstractAdapter
0
+
0
+ def typecast_load(obj, prop)
0
+ if [Date, Time, DateTime].include?(prop.primitive)
0
+ Time.parse(obj)
0
+ else
0
+ obj
0
+ end
0
+ end
0
+
0
+ def typecast_dump(obj)
0
+ case obj
0
+ when Date, Time, DateTime
0
+ obj.strftime("%d-%b-%Y")
0
+ else
0
+ obj
0
+ end
0
+ end
0
+
0
+ end
0
+
0
+ end
0
+end
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
0
@@ -0,0 +1,87 @@
0
+module DataMapper
0
+ module Adapters
0
+
0
+ module Imap
0
+ class ImapType < DataMapper::Type
0
+ class << self
0
+ attr_reader :query_details
0
+ def imap_query(name)
0
+ @query_details = name
0
+ end
0
+
0
+ attr_reader :envelope_name
0
+ def envelope(name)
0
+ self.field "ENVELOPE"
0
+ @envelope_name = name
0
+ end
0
+
0
+ def envelope?
0
+ !!@envelope_name
0
+ end
0
+ end
0
+ end
0
+
0
+ class Uid < ImapType
0
+ primitive String
0
+ field "UID"
0
+ imap_query(:eql => ["UID"], :like => ["UID"])
0
+ end
0
+
0
+ class Body < ImapType
0
+ primitive String
0
+ field "RFC822.TEXT"
0
+ imap_query(:eql => ["BODY"], :like => ["BODY"])
0
+ end
0
+
0
+ class InternalDate < ImapType
0
+ primitive DateTime
0
+ field "INTERNALDATE"
0
+ imap_query(:lt => ["BEFORE"], :eql => ["ON"], :gt => ["SINCE"])
0
+ end
0
+
0
+ class EnvelopeDate < ImapType
0
+ primitive DateTime
0
+ envelope :date
0
+ imap_query(:lt => ["SENTBEFORE"], :eql => ["SENTON"], :gt => ["SENTSINCE"])
0
+ end
0
+
0
+ class Size < ImapType
0
+ primitive Integer
0
+ field "RFC822.SIZE"
0
+ imap_query(:lt => ["SMALLER"], :gt => ["LARGER"])
0
+ end
0
+
0
+ class Header < ImapType
0
+ primitive String
0
+ field "BODY.PEEK[HEADER]"
0
+ imap_query(:eql => ["HEADER"])
0
+ end
0
+
0
+ {:from => ["FROM"], :sender => ["HEADER", "Sender"],
0
+ :to => ["TO"], :reply_to => ["HEADER", "Reply-To"],
0
+ :cc => ["CC"], :bcc => ["BCC"]}.each do |kind, imap_query|
0
+ self.class_eval <<-HERE
0
+ class #{Inflection.camelize(kind.to_s)} < ImapType
0
+ primitive Object
0
+ envelope :#{kind}
0
+ imap_query(:eql => #{imap_query.inspect}, :like => #{imap_query.inspect})
0
+ end
0
+ HERE
0
+ end
0
+
0
+ {:subject => ["SUBJECT"], :in_reply_to => ["HEADER", "In-Reply-To"],
0
+ :message_id => ["HEADER", "Message-ID"]}.each do |kind, imap_query|
0
+ self.class_eval <<-HERE
0
+ class #{Inflection.camelize(kind.to_s)} < ImapType
0
+ primitive String
0
+ envelope :#{kind}
0
+ imap_query(:eql => #{imap_query.inspect}, :like => #{imap_query.inspect})
0
+ end
0
+ HERE
0
+ end
0
+
0
+ end
0
+
0
+ end
0
+end
0
+
0
\ No newline at end of file

Comments

    No one has commented yet.