gephi_keeper 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2011-10-30
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,15 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ bin/gephi_keeper
7
+ lib/gephi_keeper.rb
8
+ lib/gephi_keeper/base.rb
9
+ lib/gephi_keeper/cli.rb
10
+ script/console
11
+ script/destroy
12
+ script/generate
13
+ test/test_gephi_keeper.rb
14
+ test/test_gephi_keeper_cli.rb
15
+ test/test_helper.rb
@@ -0,0 +1 @@
1
+ Gratz! You can now run 'gephi_keeper -f FILENAME'
@@ -0,0 +1,85 @@
1
+ = gephi_keeper
2
+
3
+ * http://github.com/cmdjohnson/gephi_keeper
4
+
5
+ == DESCRIPTION:
6
+
7
+ gephi_keeper is a Ruby conversion gem that links YourTwapperKeeper (http://your.twapperkeeper.com/) to Gephi (http://www.gephi.org) by converting JSON output from YTK to Gephi's GEXF format.
8
+
9
+ YourTwapperKeeper is a self-hosted service that archives tweets. Gephi is a graph visualization tool. YTK exports the archived tweets in a number of formats, one of which is JSON. The JSON files produced by YTK are converted by gephi_keeper into Gephi-readable GEXF files.
10
+
11
+ The GEXF files can then be processed by Gephi to produce colorful graph representations of Twitter output.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ - Dynamic graphs: use the Gephi timeline to watch the network evolve over time.
16
+ - Attributes: Number of tweets per user, number of mentions per user.
17
+ - Node color is based on Twitter activity: a very active user is colored red whilst a not-so-active user is black.
18
+ - Node size is based on other Twitter users' activity: a user that is mentioned many times is larger than a user that is not.
19
+ - Parents: when user A mentions user B, user B becomes A's parent.
20
+ - Edges are plotted automatically between interacting users: when user A mentions user B, an edge is created.
21
+ - Edge weight is based on the activity from user A to user B. When user A mentions B many times, the edge weight in increased.
22
+
23
+ == SYNOPSIS:
24
+
25
+ Input a file into gephi_keeper and pipe the output to a gzipped output file:
26
+
27
+ $ gephi_keeper -f input_file.json | gzip > output_file.gexf.gz
28
+
29
+ == REQUIREMENTS:
30
+
31
+ gephi_keeper needs these gems in order to run properly:
32
+ - json (for JSON input)
33
+ - options_checker
34
+ - builder (for XML output)
35
+
36
+ == INSTALL:
37
+
38
+ $ sudo gem install gephi_keeper
39
+
40
+ == EXAMPLES:
41
+
42
+ Screenshots:
43
+
44
+ https://github.com/cmdjohnson/gephi_keeper/raw/master/examples/screenshots/twitter_gephi_keeper_1.png
45
+
46
+ https://github.com/cmdjohnson/gephi_keeper/raw/master/examples/screenshots/twitter_gephi_keeper_2.png
47
+
48
+ Recipe used for the screenshots:
49
+ 1. Import oracle.gexf
50
+ 2. Layout: Fruchterman Reingold
51
+ 3. Enable labels
52
+ 4. Rank label size based on num_mentions, min_size = 0.5 and max_size = 3
53
+
54
+ Example Gephi files:
55
+
56
+ Hashtag #oracle (3,000 tweets) https://github.com/cmdjohnson/gephi_keeper/raw/master/examples/output/oracle.gexf.gz
57
+
58
+ Hashtag #java (5,000 tweets) https://github.com/cmdjohnson/gephi_keeper/raw/master/examples/output/java.gexf.gz
59
+
60
+ Hashtag #twitter (10,000 tweets) https://github.com/cmdjohnson/gephi_keeper/raw/master/examples/output/twitter.gexf.gz
61
+
62
+ == LICENSE:
63
+
64
+ (The MIT License)
65
+
66
+ Copyright (c) 2011 Commander Johnson <commanderjohnson@gmail.com>
67
+
68
+ Permission is hereby granted, free of charge, to any person obtaining
69
+ a copy of this software and associated documentation files (the
70
+ 'Software'), to deal in the Software without restriction, including
71
+ without limitation the rights to use, copy, modify, merge, publish,
72
+ distribute, sublicense, and/or sell copies of the Software, and to
73
+ permit persons to whom the Software is furnished to do so, subject to
74
+ the following conditions:
75
+
76
+ The above copyright notice and this permission notice shall be
77
+ included in all copies or substantial portions of the Software.
78
+
79
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
80
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
81
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
82
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
83
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
84
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
85
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/gephi_keeper'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'gephi_keeper' do
14
+ self.developer 'Commander Johnson', 'commanderjohnson@gmail.com'
15
+ self.post_install_message = 'PostInstall.txt'
16
+ self.rubyforge_name = self.name
17
+ self.extra_deps = [ "json", "options_checker", "builder" ]
18
+
19
+ end
20
+
21
+ require 'newgem/tasks'
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
23
+
24
+ # TODO - want other tests/tasks run by default? Add them to the list
25
+ # remove_task :default
26
+ # task :default => [:spec, :features]
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Commander Johnson on 2011-10-30.
4
+ # Copyright (c) 2011. All rights reserved.
5
+
6
+ require 'rubygems'
7
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/gephi_keeper")
8
+ require "gephi_keeper/cli"
9
+
10
+ GephiKeeper::CLI.execute(STDOUT, ARGV)
@@ -0,0 +1,6 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module GephiKeeper
5
+ VERSION = '0.0.1'
6
+ end
@@ -0,0 +1,301 @@
1
+ require 'rubygems'
2
+ # json
3
+ require 'json'
4
+ # options_checker
5
+ require 'options_checker'
6
+ # builder
7
+ require 'builder'
8
+ # time
9
+ # for 'parse'
10
+ require 'time'
11
+
12
+ module GephiKeeper
13
+ class Base
14
+ def self.process_file(options = {})
15
+ OptionsChecker.check(options, [ :filename ])
16
+
17
+ ##########################################################################
18
+ # initialize
19
+ ##########################################################################
20
+
21
+ # Get file object
22
+ file = File.new(options[:filename])
23
+ # Load the file into memory. Could be costly when files are too big ...
24
+ json = JSON.parse(file.read)
25
+
26
+ ##########################################################################
27
+ # metadata
28
+ ##########################################################################
29
+
30
+ # Metadata
31
+ create_time = json["archive_info"]["create_time"]
32
+ tags = json["archive_info"]["tags"]
33
+ id = json["archive_info"]["id"]
34
+ count = json["archive_info"]["count"]
35
+ user_id = json["archive_info"]["user_id"]
36
+ description = json["archive_info"]["description"]
37
+ keyword = json["archive_info"]["keyword"]
38
+ screen_name = json["archive_info"]["screen_name"]
39
+
40
+ ##########################################################################
41
+ # process tweets
42
+ ##########################################################################
43
+
44
+ # les tweets
45
+ tweets = json["tweets"]
46
+
47
+ start_time = Time.parse(tweets.last["created_at"])
48
+ end_time = Time.parse(tweets.first["created_at"])
49
+ converted_start_time = convert_time_to_gexf_integer(start_time)
50
+ converted_end_time = convert_time_to_gexf_integer(end_time)
51
+
52
+ # We will convert to this
53
+ nodes = {}
54
+ edges = {}
55
+ # Generic attributes for each node in this population.
56
+ attributes = []
57
+ # Define attributes.
58
+ attributes.push({ :title => "num_tweets", :type => "integer" })
59
+ attributes.push({ :title => "num_mentions", :type => "integer" })
60
+
61
+ # But use this indirect representation first.
62
+ # +_+ #
63
+ occurrences ||= {}
64
+ # Count the number of mentions with this hash.
65
+ mentions ||= {}
66
+
67
+ # Example json tweet:
68
+ #{"archivesource":"twitter-search",
69
+ #"text":"RT @netbeans: Building a simple AtomPub client w #NetBeans, #Maven, #Java &amp; #Apache Abdera: http:\/\/t.co\/NQcUi32k",
70
+ #"to_user_id":"",
71
+ #"from_user":"banumelody",
72
+ #"id":"129498621086408704",
73
+ #"from_user_id":"277264632",
74
+ #"iso_language_code":"en",
75
+ #"source":"&lt;a href=&quot;http:\/\/www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;\/a&gt;",
76
+ #"profile_image_url":"http:\/\/a1.twimg.com\/profile_images\/1605902800\/Hytgs0pn_normal",
77
+ #"geo_type":"",
78
+ #"geo_coordinates_0":"0",
79
+ #"geo_coordinates_1":"0",
80
+ #"created_at":"Thu, 27 Oct 2011 10:04:11 +0000",
81
+ #"time":"1319709851"}
82
+
83
+ # Convert to a workable internal representation.
84
+ for tweet in tweets
85
+ #nodes.push({ :id => tweet["from_user_id"], :label => tweet["from_user"] })
86
+ # Don't distinguish oracle and Oracle.
87
+ username = tweet["from_user"].downcase
88
+ # Make the hash if it wasn't already there.
89
+ occurrences[username] ||= {}
90
+ o = occurrences[username]
91
+ # Count the number of times this user exists in this export
92
+ o ||= {}
93
+ # Tweet array.
94
+ o[:tweets] ||= []
95
+ # Now push this tweet occurence to that user.
96
+ o[:tweets].push(tweet)
97
+
98
+ # Check for the first tweet from this user.
99
+ # We are only interested in the date of the first tweet and none other.
100
+ # +_+ #
101
+ parsed_time = Time.parse(tweet["created_at"])
102
+ # Was it before the existing tweet, if any?
103
+ if o[:first_tweeted_at].nil?
104
+ my_parsed_time = parsed_time
105
+ else
106
+ my_parsed_time = parsed_time if parsed_time < o[:first_tweeted_at]
107
+ end
108
+ # +_+ #
109
+ o[:first_tweeted_at] = my_parsed_time
110
+
111
+ # Extract references.
112
+ o[:references] ||= {}
113
+ # All references in this tweet.
114
+ # +_+ #
115
+ refs = tweet["text"].scan(/@(\w+)/) # => [["netbeans"], ["zozo"], ["bozozo"]]
116
+ # +_+ #
117
+ for ref in refs
118
+ # Oracle is the same as oracle
119
+ my_ref = ref.first.downcase
120
+ # Also add this user to the nodes list.
121
+ occurrences[my_ref] ||= {}
122
+ occurrences[my_ref][:first_tweeted_at] ||= my_parsed_time
123
+ # +_+ #
124
+ o[:references][my_ref] ||= { :count => 0 }
125
+ ref_p = o[:references][my_ref]
126
+ # Increase count.
127
+ ref_p[:count] += 1
128
+ # Also increase the count of the global mentions in this population.
129
+ mentions[my_ref] ||= 0
130
+ # +_+ #
131
+ mentions[my_ref] += 1
132
+ end
133
+ end
134
+
135
+ ##########################################################################
136
+ # Data structure:
137
+ #
138
+ # occurrences
139
+ # - [username]
140
+ # - :tweets Array of tweets (Hash objects)
141
+ # - :first_tweeted_at Time object when the first tweet from this user was registered.
142
+ # - :references Hash of usernames (String) mentioned by this user in any tweet
143
+ # - [username]
144
+ # - :count Number of times referred to username in any tweet
145
+ ##########################################################################
146
+
147
+ # Now convert to nodes & edges
148
+ occurrences.keys.each do |key|
149
+ # +_+ #
150
+ node_options = {}
151
+ # +_+ #
152
+ num_tweets = 0
153
+ # +_+ #
154
+ begin
155
+ num_tweets = occurrences[key][:tweets].count
156
+ rescue
157
+ end
158
+ # +_+ #
159
+ num_mentions = mentions[key] || 0
160
+ # +_+ #
161
+ node_options = { :attributes => {
162
+ :id => key,
163
+ :label => key,
164
+ :start => convert_time_to_gexf_integer(occurrences[key][:first_tweeted_at]),
165
+ :end => converted_end_time
166
+ },
167
+ :size => num_mentions,
168
+ :intensity => num_tweets,
169
+ :attvalues => [
170
+ # 0 = tweets, 1 = mentions
171
+ { :value => num_tweets, :for => "0" },
172
+ { :value => num_mentions, :for => "1" }
173
+ ]
174
+ }
175
+ # Now using Hash instead of Array
176
+ nodes[key] = node_options
177
+ # +_+ #
178
+ if occurrences[key][:references]
179
+ occurrences[key][:references].keys.each do |reference|
180
+ # +_+ #
181
+ edge_key = "#{key}-#{reference}"
182
+ # +_+ #
183
+ reference_count = occurrences[key][:references][reference][:count]
184
+ # +_+ #
185
+ edges[edge_key] = { :id => edge_key, :source => key,
186
+ :target => reference,
187
+ :weight => reference_count,
188
+ :label => reference_count
189
+ }
190
+ end
191
+ end
192
+ end
193
+
194
+ ##########################################################################
195
+ # output xml
196
+ #
197
+ # fuck xmlsimple. Hashes don't order too well.
198
+ ##########################################################################
199
+
200
+ now = Time.now
201
+ xml_last_modified_date = convert_time_to_gexf_date(now)
202
+ xml_creator = screen_name
203
+ xml_description = "gephi_keeper GEXF output for keyword '#{keyword}' at (#{xml_last_modified_date}). Tags: '#{tags}'. Number of tweets: #{count}. Description: #{description}"
204
+
205
+ # nodes = [
206
+ # { :id => 0, :label => "Hello" },
207
+ # { :id => 1, :label => "World" } ]
208
+ # edges = [
209
+ # { :id => 0, :source => 0, :target => 1 }
210
+ # ]
211
+
212
+ xml = Builder::XmlMarkup.new( :target => $stdout, :indent => 2 )
213
+
214
+ xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
215
+
216
+ xml.gexf :xmlns => "http://www.gexf.net/1.1", :version => "1.1", "xmlns:viz" => "http://www.gexf.net/1.1draft/viz" do
217
+ xml.graph :mode => "dynamic", :start => converted_start_time, :end => converted_end_time, :timeformat => "integer" do
218
+ xml.meta :lastmodifieddate => xml_last_modified_date do
219
+ xml.creator xml_creator
220
+ xml.description xml_description
221
+ end
222
+ xml.attributes :class => :node do
223
+ for attribute in attributes
224
+ xml_attribute_options = { :id => attributes.index(attribute) }
225
+ xml.attribute xml_attribute_options.merge(attribute)
226
+ end
227
+ end
228
+ xml.nodes do
229
+ nodes.each do |key, node|
230
+ # ATTRIBUTES ATTRIBUTES ATTRIBUTES ATTRIBUTES ATTRIBUTES ATTRIBUTES
231
+ xml.node node[:attributes] do
232
+ # VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ VIZ
233
+ xml.viz :size, :value => node[:size]
234
+ xml.viz :color, intensity_to_gexf_color(node[:intensity])
235
+ # ATTVALUES ATTVALUES ATTVALUES ATTVALUES ATTVALUES ATTVALUES ATTVALUES
236
+ xml.attvalues do
237
+ for attvalue in node[:attvalues]
238
+ xml.attvalue attvalue
239
+ end
240
+ end
241
+ # PARENTS PARENTS PARENTS PARENTS PARENTS PARENTS PARENTS PARENTS
242
+ if occurrences[key][:references]
243
+ unless occurrences[key][:references].keys.count.eql?(0)
244
+ xml.parents do
245
+ occurrences[key][:references].keys.each do |reference|
246
+ xml.parent :for => reference
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end
254
+ xml.edges do
255
+ edges.each do |key, edge|
256
+ xml.edge edge
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ ##########################################################################
263
+ # fin
264
+ ##########################################################################
265
+
266
+ true
267
+ end
268
+
269
+ protected
270
+
271
+ def self.convert_time_to_gexf_date(time)
272
+ raise "Need Time object" unless time.is_a? Time
273
+
274
+ "#{time.year}-#{time.month}-#{time.day}"
275
+ end
276
+
277
+ def self.convert_time_to_gexf_integer(time)
278
+ raise "Need Time object" unless time.is_a? Time
279
+
280
+ time.to_i
281
+ end
282
+
283
+ def self.intensity_to_gexf_color(intensity)
284
+ r = 0
285
+ g = 0
286
+ b = 0
287
+ a = 0.7
288
+
289
+ r_increment = 10 * intensity
290
+ r_increment = 255 if r_increment > 255
291
+ r += r_increment
292
+
293
+ a_increment = 0.01 * intensity
294
+
295
+ a_increment = 0.3 if a_increment > 0.3
296
+ a += a_increment
297
+
298
+ { :r => r, :g => g, :b => b, :a => a }
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,41 @@
1
+ require 'optparse'
2
+ require 'gephi_keeper/base'
3
+
4
+ module GephiKeeper
5
+ class CLI
6
+ def self.execute(stdout, arguments=[])
7
+
8
+ # Defaults for options
9
+ options = {
10
+ :filename => nil
11
+ }
12
+ mandatory_options = [ :filename ]
13
+
14
+ parser = OptionParser.new do |opts|
15
+ opts.banner = <<-BANNER.gsub(/^ /,'')
16
+ Convert tweets from Twitter, output as JSON from TwapperKeeper (www.twapperkeeper.com) into GEXF format for the Gephi graphviz tool. (www.gephi.org)
17
+
18
+ Usage: #{File.basename($0)} [options]
19
+
20
+ Options are:
21
+ BANNER
22
+ opts.separator ""
23
+ opts.on("-f", "--filename FILENAME", String,
24
+ "Name of input file.") { |arg| options[:filename] = arg }
25
+ opts.on("-h", "--help",
26
+ "Show this help message.") { stdout.puts opts; exit }
27
+ opts.parse!(arguments)
28
+ # Check for mandatory options
29
+ if mandatory_options && mandatory_options.find { |option| options[option.to_sym].nil? }
30
+ stdout.puts opts; exit
31
+ end
32
+ end
33
+
34
+ filename = options[:filename]
35
+
36
+ # do stuff
37
+ #stdout.puts "To update this executable, look in lib/gephi_keeper/cli.rb"
38
+ GephiKeeper::Base.process_file( :filename => filename )
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/gephi_keeper.rb'}"
9
+ puts "Loading gephi_keeper gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestGephiKeeper < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper.rb")
2
+ require 'gephi_keeper/cli'
3
+
4
+ class TestGephiKeeperCli < Test::Unit::TestCase
5
+ def setup
6
+ GephiKeeper::CLI.execute(@stdout_io = StringIO.new, [])
7
+ @stdout_io.rewind
8
+ @stdout = @stdout_io.read
9
+ end
10
+
11
+ def test_print_default_output
12
+ assert_match(/To update this executable/, @stdout)
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/gephi_keeper'
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gephi_keeper
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Commander Johnson
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-25 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: options_checker
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: builder
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: hoe
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 47
72
+ segments:
73
+ - 2
74
+ - 8
75
+ - 0
76
+ version: 2.8.0
77
+ type: :development
78
+ version_requirements: *id004
79
+ description: |-
80
+ gephi_keeper is a Ruby conversion gem that links YourTwapperKeeper (http://your.twapperkeeper.com/) to Gephi (http://www.gephi.org) by converting JSON output from YTK to Gephi's GEXF format.
81
+
82
+ YourTwapperKeeper is a self-hosted service that archives tweets. Gephi is a graph visualization tool. YTK exports the archived tweets in a number of formats, one of which is JSON. The JSON files produced by YTK are converted by gephi_keeper into Gephi-readable GEXF files.
83
+
84
+ The GEXF files can then be processed by Gephi to produce colorful graph representations of Twitter output.
85
+ email:
86
+ - commanderjohnson@gmail.com
87
+ executables:
88
+ - gephi_keeper
89
+ extensions: []
90
+
91
+ extra_rdoc_files:
92
+ - History.txt
93
+ - Manifest.txt
94
+ - PostInstall.txt
95
+ files:
96
+ - History.txt
97
+ - Manifest.txt
98
+ - PostInstall.txt
99
+ - README.rdoc
100
+ - Rakefile
101
+ - bin/gephi_keeper
102
+ - lib/gephi_keeper.rb
103
+ - lib/gephi_keeper/base.rb
104
+ - lib/gephi_keeper/cli.rb
105
+ - script/console
106
+ - script/destroy
107
+ - script/generate
108
+ - test/test_gephi_keeper.rb
109
+ - test/test_gephi_keeper_cli.rb
110
+ - test/test_helper.rb
111
+ has_rdoc: true
112
+ homepage: http://github.com/cmdjohnson/gephi_keeper
113
+ licenses: []
114
+
115
+ post_install_message: PostInstall.txt
116
+ rdoc_options:
117
+ - --main
118
+ - README.rdoc
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: 3
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ hash: 3
136
+ segments:
137
+ - 0
138
+ version: "0"
139
+ requirements: []
140
+
141
+ rubyforge_project: gephi_keeper
142
+ rubygems_version: 1.3.7
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: gephi_keeper is a Ruby conversion gem that links YourTwapperKeeper (http://your.twapperkeeper.com/) to Gephi (http://www.gephi.org) by converting JSON output from YTK to Gephi's GEXF format
146
+ test_files:
147
+ - test/test_gephi_keeper.rb
148
+ - test/test_gephi_keeper_cli.rb
149
+ - test/test_helper.rb