gnip 0.4.2

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.
Files changed (89) hide show
  1. data/README +144 -0
  2. data/Rakefile +53 -0
  3. data/TODO +72 -0
  4. data/bin/gnip +651 -0
  5. data/doc/api.html +1201 -0
  6. data/gemspec.rb +47 -0
  7. data/gnip-0.4.2.gem +0 -0
  8. data/lib/gnip.rb +71 -0
  9. data/lib/gnip/activity.rb +663 -0
  10. data/lib/gnip/api.rb +191 -0
  11. data/lib/gnip/arguments.rb +21 -0
  12. data/lib/gnip/blankslate.rb +5 -0
  13. data/lib/gnip/config.rb +144 -0
  14. data/lib/gnip/filter.rb +304 -0
  15. data/lib/gnip/list.rb +126 -0
  16. data/lib/gnip/options.rb +96 -0
  17. data/lib/gnip/orderedhash.rb +199 -0
  18. data/lib/gnip/publisher.rb +309 -0
  19. data/lib/gnip/resource.rb +301 -0
  20. data/lib/gnip/template.rb +44 -0
  21. data/lib/gnip/util.rb +120 -0
  22. data/sample/data/activity.yml +21 -0
  23. data/test/auth.rb +60 -0
  24. data/test/config.yml +2 -0
  25. data/test/data/activity.xml +14 -0
  26. data/test/data/activity_only_required.xml +4 -0
  27. data/test/data/activity_with_payload.xml +22 -0
  28. data/test/data/activity_with_place.xml +18 -0
  29. data/test/data/activity_with_place_wo_bounds.xml +36 -0
  30. data/test/data/activity_with_unbounded_media_urls.xml +44 -0
  31. data/test/data/activity_without_bounds.xml +24 -0
  32. data/test/helper.rb +115 -0
  33. data/test/helper.rb.bak +28 -0
  34. data/test/integration/auth.rb +12 -0
  35. data/test/integration/publisher.rb +86 -0
  36. data/test/lib/shoulda.rb +9 -0
  37. data/test/lib/shoulda/action_controller.rb +28 -0
  38. data/test/lib/shoulda/action_controller/helpers.rb +47 -0
  39. data/test/lib/shoulda/action_controller/macros.rb +277 -0
  40. data/test/lib/shoulda/action_controller/matchers.rb +37 -0
  41. data/test/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  42. data/test/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  43. data/test/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  44. data/test/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +70 -0
  45. data/test/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +77 -0
  46. data/test/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  47. data/test/lib/shoulda/action_controller/matchers/set_session_matcher.rb +83 -0
  48. data/test/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  49. data/test/lib/shoulda/action_mailer.rb +10 -0
  50. data/test/lib/shoulda/action_mailer/assertions.rb +38 -0
  51. data/test/lib/shoulda/action_view.rb +10 -0
  52. data/test/lib/shoulda/action_view/macros.rb +56 -0
  53. data/test/lib/shoulda/active_record.rb +16 -0
  54. data/test/lib/shoulda/active_record/assertions.rb +69 -0
  55. data/test/lib/shoulda/active_record/helpers.rb +40 -0
  56. data/test/lib/shoulda/active_record/macros.rb +586 -0
  57. data/test/lib/shoulda/active_record/matchers.rb +42 -0
  58. data/test/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  59. data/test/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  60. data/test/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  61. data/test/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  62. data/test/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  63. data/test/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  64. data/test/lib/shoulda/active_record/matchers/have_index_matcher.rb +105 -0
  65. data/test/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +125 -0
  66. data/test/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  67. data/test/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  68. data/test/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  69. data/test/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  70. data/test/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  71. data/test/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
  72. data/test/lib/shoulda/assertions.rb +59 -0
  73. data/test/lib/shoulda/autoload_macros.rb +46 -0
  74. data/test/lib/shoulda/context.rb +304 -0
  75. data/test/lib/shoulda/helpers.rb +8 -0
  76. data/test/lib/shoulda/macros.rb +73 -0
  77. data/test/lib/shoulda/private_helpers.rb +20 -0
  78. data/test/lib/shoulda/proc_extensions.rb +14 -0
  79. data/test/lib/shoulda/rails.rb +13 -0
  80. data/test/lib/shoulda/rspec.rb +9 -0
  81. data/test/lib/shoulda/tasks.rb +3 -0
  82. data/test/lib/shoulda/tasks/list_tests.rake +29 -0
  83. data/test/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  84. data/test/lib/shoulda/test_unit.rb +19 -0
  85. data/test/lib/xmlsimple.rb +1021 -0
  86. data/test/loader.rb +25 -0
  87. data/test/unit/activity.rb +26 -0
  88. data/test/unit/util.rb +39 -0
  89. metadata +198 -0
data/lib/gnip/api.rb ADDED
@@ -0,0 +1,191 @@
1
+ module Gnip
2
+
3
+ # TODO - doc the api
4
+
5
+ module Api
6
+ #
7
+ #
8
+ def username(*arg)
9
+ default.config.username = arg.first.to_s unless arg.empty?
10
+ default.config.username
11
+ end
12
+ alias_method 'username=', 'username'
13
+
14
+ def password(*arg)
15
+ default.config.password = arg.first.to_s unless arg.empty?
16
+ default.config.password
17
+ end
18
+ alias_method 'password=', 'password'
19
+
20
+ def uri(*arg)
21
+ default.config.uri = arg.first.to_s unless arg.empty?
22
+ default.config.uri
23
+ end
24
+ alias_method 'uri=', 'uri'
25
+
26
+ #
27
+ #
28
+ def ping(*args)
29
+ args, options = Gnip.args_for(args)
30
+ path = args.shift || Gnip.default.ping_path
31
+ options = Gnip.options_for(options)
32
+ resource = options.getopt(:resource, Gnip.default.resource)
33
+ endpoint = resource.endpoint(path)
34
+ !!endpoint.get
35
+ rescue
36
+ raise if options.getopt(:raise)
37
+ false
38
+ end
39
+
40
+ #
41
+ #
42
+ def publisher
43
+ Publisher
44
+ end
45
+
46
+ #
47
+ #
48
+ def resource
49
+ Resource
50
+ end
51
+
52
+ #
53
+ #
54
+ def activity
55
+ Activity
56
+ end
57
+
58
+ #
59
+ #
60
+ def filter
61
+ Filter
62
+ end
63
+
64
+ #
65
+ #
66
+ def util
67
+ Util
68
+ end
69
+
70
+ #
71
+ #
72
+ def config
73
+ Config
74
+ end
75
+
76
+ #
77
+ #
78
+ def orderedhash
79
+ OrderedHash
80
+ end
81
+
82
+ #
83
+ #
84
+ def clock_drift(*args)
85
+ args, options = Gnip.args_for(args)
86
+ path = args.shift || Gnip.default.ping_path
87
+ options = Gnip.options_for(options)
88
+ resource = options.getopt(:resource, Gnip.default.resource)
89
+ force = options.getopt(:force, false)
90
+ endpoint = resource.endpoint(path)
91
+ @clock_drift = nil if force
92
+ @clock_drift ||= ( Time.httpdate(endpoint.get.headers[:date]).utc - Time.now.utc )
93
+ end
94
+
95
+ #
96
+ #
97
+ def Gnip.time
98
+ Time.now.utc + clock_drift
99
+ end
100
+
101
+ #
102
+ #
103
+ attr_writer 'scope'
104
+
105
+ def scope *arg, &block
106
+ @scope ||= Gnip.default.scope
107
+ if block
108
+ scope = @scope
109
+ begin
110
+ @scope = arg.first.to_s unless arg.empty?
111
+ block.call(@scope)
112
+ ensure
113
+ @scope = scope
114
+ end
115
+ end
116
+ @scope
117
+ end
118
+
119
+ #
120
+ #
121
+ def args_for(args)
122
+ Arguments.for(args)
123
+ end
124
+ def argify!(args)
125
+ Arguments.for(args)
126
+ end
127
+
128
+ def options_for(args)
129
+ Options.for(args)
130
+ end
131
+ def optify!(args)
132
+ Options.for(args)
133
+ end
134
+
135
+ #
136
+ #
137
+ def compress(data)
138
+ util.compress(data)
139
+ end
140
+
141
+ #
142
+ #
143
+ def decompress(data)
144
+ util.decompress(data)
145
+ end
146
+
147
+ #
148
+ #
149
+ def encode(data)
150
+ util.encode(data)
151
+ end
152
+
153
+ #
154
+ #
155
+ def decode(data)
156
+ util.decode(data)
157
+ end
158
+
159
+
160
+ #
161
+ #
162
+ module Default
163
+ @uri = 'https://api-v21.gnip.com/'
164
+ attr_accessor :uri
165
+
166
+ @scope = 'gnip'
167
+ attr_accessor :scope
168
+
169
+ @ping_path = '/my/publishers.xml'
170
+ attr_accessor :ping_path
171
+
172
+ attr_writer :config
173
+ def config
174
+ @config ||= Config.default
175
+ end
176
+
177
+ attr_writer :resource
178
+ def resource
179
+ @resource ||= Resource.default
180
+ end
181
+
182
+ extend self
183
+ end
184
+
185
+ def default
186
+ Default
187
+ end
188
+ end
189
+
190
+ extend Api
191
+ end
@@ -0,0 +1,21 @@
1
+ module Gnip
2
+ module Arguments
3
+ def options
4
+ @options ||= Options.for(last.is_a?(Hash) ? pop : {})
5
+ end
6
+
7
+ %w[ getopt getopts hasopt hasopts delopt delopts ].each do |method|
8
+ module_eval <<-code
9
+ def #{ method }(*args, &block)
10
+ options.#{ method }(*args, &block)
11
+ end
12
+ code
13
+ end
14
+
15
+ def Arguments.for(args)
16
+ raise ArgumentError unless args.is_a?(Array)
17
+ args.extend(Arguments)
18
+ [args, args.options]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Gnip
2
+ class BlankSlate
3
+ instance_methods.each{|m| undef_method m unless m =~ /^__/}
4
+ end
5
+ end
@@ -0,0 +1,144 @@
1
+ module Gnip
2
+ class Config
3
+ def Config.for(arg)
4
+ config = new
5
+ updates =
6
+ case arg
7
+ when Hash
8
+ arg
9
+ when NilClass
10
+ {}
11
+ else
12
+ if arg.respond_to?(:read)
13
+ YAML.load(arg.read)
14
+ else
15
+ YAML.load(IO.read(arg.to_s))
16
+ end
17
+ end
18
+ config.update(updates)
19
+ config
20
+ end
21
+
22
+ def Config.default_path
23
+ File.join(Gnip.util.homedir, '.gnip.yml')
24
+ end
25
+
26
+ def Config.default
27
+ @default ||= (
28
+ update_from_env(
29
+ begin
30
+ Config.for(default_path)
31
+ rescue Errno::ENOENT
32
+ Config.for(nil)
33
+ end
34
+ )
35
+ )
36
+ end
37
+
38
+ def Config.update_from_env config
39
+ username = ENV['GNIP_USERNAME']
40
+ password = ENV['GNIP_PASSWORD']
41
+ auth = ENV['GNIP_AUTH']
42
+ if(auth and not (username and password))
43
+ username, password = auth.split(%r/:/, 2)
44
+ end
45
+ uri = ENV['GNIP_URI'] || Gnip.default.uri
46
+ config.username = username if username
47
+ config.password = password if password
48
+ config.uri = uri if uri
49
+ config
50
+ end
51
+
52
+ def Config.normalized hash
53
+ stringified_keys(hash)
54
+ end
55
+
56
+ def Config.stringified_keys hash
57
+ hash.keys.inject(Hash.new){|h,k| h.update(k.to_s => hash.fetch(k))}
58
+ end
59
+
60
+ attr :config
61
+
62
+ def initialize options = {}
63
+ @config = {}
64
+ options.each do |key, value|
65
+ msg = "#{ key }="
66
+ if respond_to?(msg)
67
+ send msg, value
68
+ else
69
+ @config[key.to_s] = value
70
+ end
71
+ end
72
+ end
73
+
74
+ alias_method 'to_hash', 'config'
75
+
76
+ def to_yaml(*args, &block)
77
+ to_hash.to_yaml(*args, &block)
78
+ end
79
+
80
+ def username= username
81
+ config['username'] = username.to_s
82
+ end
83
+ def username
84
+ config['username'].to_s
85
+ end
86
+
87
+ def password= password
88
+ config['password'] = password.to_s
89
+ end
90
+ def password
91
+ config['password'].to_s
92
+ end
93
+
94
+ def uri= uri
95
+ config['uri'] = uri.to_s
96
+ end
97
+ def uri
98
+ URI.parse(config['uri'].to_s) if config['uri']
99
+ end
100
+
101
+ def inspect
102
+ config.inspect
103
+ end
104
+
105
+ def normalize!
106
+ config.replace normalized
107
+ end
108
+
109
+ def normalized hash = config
110
+ Config.normalized(hash)
111
+ end
112
+
113
+ def [] key
114
+ config[key.to_s]
115
+ end
116
+ alias_method 'get', '[]'
117
+
118
+ def []= key, val
119
+ config[key.to_s] = val
120
+ end
121
+ alias_method 'set', '[]='
122
+
123
+ def has_key? key
124
+ config.has_key? key.to_s
125
+ end
126
+
127
+ def update hash
128
+ config.update normalized(hash)
129
+ self
130
+ end
131
+
132
+ def method_missing m, *a, &b
133
+ key, setter = m.to_s.split(/(=)/)
134
+ if setter
135
+ val = a.first
136
+ return(set(key, val))
137
+ end
138
+ if has_key?(key)
139
+ return(get(key))
140
+ end
141
+ super
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,304 @@
1
+ module Gnip
2
+ class Filter
3
+ def Filter.list_from_xml(xml, options = {}, &block)
4
+ list = []
5
+ parse_xml(xml, options) do |filter|
6
+ block ? block.call(filter) : list.push(filter)
7
+ end
8
+ block ? nil : list
9
+ end
10
+
11
+ def Filter.parse_xml(xml, options = {}, &block)
12
+ doc = Nokogiri::XML.parse(xml)
13
+ list = []
14
+ selectors = 'filter'
15
+ selectors.each do |selector|
16
+ search = doc.search(selector)
17
+ next unless search.size > 0
18
+ search.each do |node|
19
+ filter = Filter.from_node(node, options)
20
+ block ? block.call(filter) : list.push(filter)
21
+ end
22
+ end
23
+ block ? nil : list
24
+ end
25
+
26
+ def Filter.from_node(node, options = {})
27
+ full_data = node['fullData'] =~ /true/ ? true : false
28
+ name = node['name']
29
+ post_url = nil
30
+ rules = []
31
+ node.search('rule').each do |rule_node|
32
+ type = rule_node['type']
33
+ value = rule_node.content
34
+ rules << {:type => type, :value => value}
35
+ end
36
+ if post_url_node = node.at('postURL')
37
+ post_url = post_url_node.content
38
+ end
39
+ new(name, rules, :full_data => full_data, :post_url => post_url)
40
+ end
41
+
42
+ def Filter.from_xml(xml, options = {})
43
+ parse_xml(xml, options){|filter| return filter}
44
+ end
45
+
46
+ Attributes = []
47
+
48
+ Attributes << 'name'
49
+ def name
50
+ @name ||= nil
51
+ end
52
+ def name= value
53
+ @name = String(value)
54
+ ensure
55
+ raise ArgumentError, @name unless @name =~ %r/^[a-zA-Z0-9.+-]+$/
56
+ end
57
+
58
+ Attributes << 'post_url'
59
+ def post_url
60
+ @post_url ||= nil
61
+ end
62
+ def post_url= value
63
+ @post_url = String(value)
64
+ end
65
+
66
+ Attributes << 'rules'
67
+ def rules
68
+ @rules ||= List.of(Rule)
69
+ end
70
+ def rules= value
71
+ rules.replace(value)
72
+ end
73
+
74
+ Attributes << 'full_data'
75
+ def full_data
76
+ @full_data ||= nil
77
+ end
78
+ def full_data= value
79
+ @full_data = !!value
80
+ end
81
+
82
+ attr_accessor :publisher
83
+
84
+ def initialize(*args)
85
+ args, options = Gnip.args_for(args)
86
+ self.name = args.shift unless args.empty?
87
+ self.rules = args unless args.empty?
88
+ options.each{|key, value| send("#{ key }=", value)}
89
+ end
90
+
91
+ class Rule
92
+ def Rule.from_xml(xml, options = {})
93
+ parse_xml(xml, options){|rule| return rule}
94
+ end
95
+
96
+ def Rule.parse_xml(xml, options = {}, &block)
97
+ doc = Nokogiri::XML.parse(xml)
98
+ list = []
99
+ selectors = 'rule'
100
+ selectors.each do |selector|
101
+ search = doc.search(selector)
102
+ next unless search.size > 0
103
+ search.each do |node|
104
+ rule = Rule.from_node(node, options)
105
+ block ? block.call(rule) : list.push(rule)
106
+ end
107
+ end
108
+ block ? nil : list
109
+ end
110
+
111
+ def Rule.from_node(node, options = {})
112
+ type = node['type']
113
+ value = node.content
114
+ new(:type => type, :value => value)
115
+ end
116
+
117
+ def Rule.for(*args)
118
+ arg = args.first if args.size == 1
119
+ if Rule === arg
120
+ arg
121
+ elsif Hash === arg
122
+ new(arg)
123
+ else
124
+ new(*args)
125
+ end
126
+ end
127
+
128
+ attr_accessor :type
129
+ attr_accessor :value
130
+
131
+ def initialize(*args)
132
+ args, options = Gnip.args_for(args)
133
+ type = value = nil
134
+ case args.size
135
+ when 1
136
+ type, value = args.first.to_s.split(%r/:/, 2)
137
+ when 2
138
+ type, value = args
139
+ end
140
+ self.type = Publisher.rule.for options.getopt(:type, type)
141
+ self.value = options.getopt(:value, value)
142
+ end
143
+
144
+ def inspect
145
+ "#{ type }:#{ value }"
146
+ end
147
+
148
+ def to_s
149
+ inspect
150
+ end
151
+
152
+ def to_yaml(*a, &b)
153
+ to_s.to_yaml(*a, &b)
154
+ end
155
+
156
+ =begin
157
+ def Rule.template
158
+ @template ||=
159
+ Template.new do
160
+ "
161
+ <rule type=<%= type.inspect %>>
162
+ <%= value %>
163
+ </rule>
164
+ "
165
+ end
166
+ end
167
+
168
+ def to_xml(options = {})
169
+ Rule.template.expand(self)
170
+ end
171
+ =end
172
+
173
+ include Tagz
174
+ def to_xml(*args)
175
+ args, options = Gnip.args_for(args)
176
+ doc = args.shift
177
+
178
+ tagz(doc) {
179
+ rule_(:type => type){ value }
180
+ }
181
+ end
182
+
183
+ attr_accessor :filter
184
+
185
+ def resource
186
+ raise 'filter not set!' unless filter
187
+ rule = self
188
+ filter.publisher.filter.resource["filters/#{ filter.name }/rules?type=#{ rule.type }&value=#{ rule.value }"]
189
+ end
190
+
191
+ def delete(options = {})
192
+ Gnip.optify!(options)
193
+ filter = options.getopt(:filter, self.filter)
194
+ resource.delete
195
+ self
196
+ end
197
+ end
198
+
199
+ include Tagz
200
+ def to_xml(*args)
201
+ tagz {
202
+ filter_(:name => name, :fullData => !!full_data){
203
+ rules.each do |rule|
204
+ rule_(:type => rule.type){ rule.value }
205
+ end
206
+ }
207
+ }
208
+ end
209
+
210
+ =begin
211
+ def Filter.template
212
+ @template ||=
213
+ Template.new do
214
+ "
215
+ <filter name=<%= name.inspect %> fullData=<%= (!!full_data).to_s.inspect %>>
216
+ % if post_url
217
+ <postURL><%= post_url %></postURL>
218
+ % end
219
+ % rules.each do |rule|
220
+ <rule type=<%= rule.type.inspect %>><%= rule.value %></rule>
221
+ % end
222
+ </filter>
223
+ "
224
+ end
225
+ end
226
+
227
+ def to_xml(options = {})
228
+ Filter.template.expand(self)
229
+ end
230
+ =end
231
+
232
+ def resource
233
+ raise 'publisher not set!' unless publisher
234
+ publisher.filter.resource["filters/#{ name }.xml"]
235
+ end
236
+
237
+ def get(*args, &block)
238
+ resource.get(*args, &block)
239
+ end
240
+
241
+ def delete(*args, &block)
242
+ resource.delete(*args, &block)
243
+ end
244
+
245
+ def put(*args, &block)
246
+ resource.put(*args, &block)
247
+ end
248
+
249
+ def post(*args, &block)
250
+ resource.post(*args, &block)
251
+ end
252
+
253
+ def replace(other)
254
+ put(other.to_xml)
255
+ publisher.filter.for(name)
256
+ end
257
+
258
+ def rule
259
+ @rule ||= RuleResource.new(self)
260
+ end
261
+
262
+ class RuleResource
263
+ attr_accessor :filter
264
+
265
+ def initialize filter
266
+ @filter = filter
267
+ end
268
+
269
+ def publisher
270
+ filter.publisher
271
+ end
272
+
273
+ def resource
274
+ publisher.resource
275
+ end
276
+
277
+ def list options = {}
278
+ Gnip.optify!(options)
279
+ type = options.getopt(:type) or raise 'no type'
280
+ value = options.getopt(:value) or raise 'no type'
281
+ xml = resource["filters/#{ filter.name }/rules?type=#{ type }&value=#{ value }"].get
282
+ rule = Rule.from_xml(xml)
283
+ rule.filter = filter
284
+ rule
285
+ end
286
+
287
+ def delete options = {}
288
+ list(options).delete(:filter => filter)
289
+ end
290
+
291
+ def create(*rules)
292
+ rules = rules.map{|rule| Rule.for(rule)}
293
+ slices = [] and rules.each_slice(5000){|slice| slices << slice}
294
+ msg = slices.size > 1 ? 'threadify' : 'each'
295
+ slices.send(msg) do |slice|
296
+ xml = slice.map{|rule| rule.to_xml(:declaration => false)}.join
297
+ resource["filters/#{ filter.name }/rules"].post("<rules>#{ xml }</rules>")
298
+ end
299
+ rules.each{|rule| rule.filter = filter}
300
+ rules
301
+ end
302
+ end
303
+ end
304
+ end