thimbl 0.0.1 → 0.0.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.
data/Gemfile CHANGED
@@ -1,5 +1,11 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
+ gem 'json'
4
+ gem 'net-scp'
5
+
3
6
  group :test do
7
+ gem 'echoe'
4
8
  gem 'mocha'
9
+ gem 'delorean'
10
+ gem 'ruby-debug'
5
11
  end
data/Gemfile.lock ADDED
@@ -0,0 +1,42 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ chronic (0.3.0)
5
+ columnize (0.3.2)
6
+ delorean (0.2.1)
7
+ chronic
8
+ echoe (4.3.1)
9
+ gemcutter
10
+ rubyforge
11
+ fileutils (0.6)
12
+ rmagick (>= 2.13.1)
13
+ gemcutter (0.6.1)
14
+ json (1.5.1)
15
+ json_pure (1.5.1)
16
+ linecache (0.43)
17
+ mocha (0.9.11)
18
+ rake
19
+ net-scp (1.0.4)
20
+ net-ssh (>= 1.99.1)
21
+ net-ssh (2.1.0)
22
+ rake (0.8.7)
23
+ rmagick (2.13.1)
24
+ ruby-debug (0.10.4)
25
+ columnize (>= 0.1)
26
+ ruby-debug-base (~> 0.10.4.0)
27
+ ruby-debug-base (0.10.4)
28
+ linecache (>= 0.3)
29
+ rubyforge (2.0.4)
30
+ json_pure (>= 1.1.7)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ delorean
37
+ echoe
38
+ fileutils
39
+ json
40
+ mocha
41
+ net-scp
42
+ ruby-debug
data/Manifest CHANGED
@@ -1,9 +1,16 @@
1
1
  Gemfile
2
+ Gemfile.lock
2
3
  Manifest
3
4
  README.md
4
5
  Rakefile
5
- lib/finger.rb
6
+ bin/thimbl
6
7
  lib/thimbl.rb
8
+ lib/thimbl/base.rb
9
+ lib/thimbl/command.rb
10
+ lib/thimbl/finger.rb
7
11
  test/fixtures/cache.json
8
- test/thimbl_test.rb
9
- thimbl.rb
12
+ test/fixtures/finger_dk_telekommunisten_org.txt
13
+ test/fixtures/finger_dk_telekommunisten_org_two_break_lines.txt
14
+ test/test_helper.rb
15
+ test/thimbl_base_test.rb
16
+ test/thimbl_command_test.rb
data/README.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Thimbl Client
2
2
 
3
- Is an small client for the distributed microbloging protocol: [thimbl](http://www.thimbl.net/)
3
+ Is an small client for the distributed microbloging protocol: [thimbl](http://thimbl.net/)
4
+
5
+ I have follow the style of the [Thimbl Python client](https://github.com/blippy/Thimbl-CLI) in many ways.
6
+
7
+ ## Commands
8
+
9
+ * setup
10
+ * follow
11
+ * fetch
12
+ * post
13
+ * print
14
+
15
+ ## Architecture
16
+
17
+ This client is only manipulating json files, the one with your **personal plan** and the other with the **complete cache** of the timeline of the people you are following.
4
18
 
5
19
  ## Version
6
20
 
@@ -8,21 +22,40 @@ This version is in development, not ready for any production environment.
8
22
 
9
23
  ## Install
10
24
 
11
- gem install thimbl
25
+ gem install thimbl
12
26
 
13
27
  ## Use
14
28
 
29
+ require 'rubygems'
15
30
  require 'thimbl'
16
- thimbl = Thimbl.new( '/tmp/plan', '/tmp/thimbl_cache' )
31
+ thimbl =
32
+ Thimbl.new(
33
+ 'plan_path' => '/tmp/plan',
34
+ 'cache_path' => '/tmp/thimbl_cache',
35
+ 'user' => 'fguillen@thimblserver.com'
36
+ 'password' => 'my_thimblserver_password'
37
+ )
17
38
  thimbl.setup(
18
- :bio => 'my bio',
19
- :website => 'my website',
20
- :mobile => 'my mobile',
21
- :email => 'my email',
22
- :address => 'my address',
23
- :name => 'my name'
39
+ 'bio' => 'my bio',
40
+ 'website' => 'my website',
41
+ 'mobile' => 'my mobile',
42
+ 'email' => 'my email',
43
+ 'address' => 'my address',
44
+ 'name' => 'my name'
24
45
  )
25
46
  thimbl.follow 'dk', 'dk@telekommunisten.org'
26
47
  thimbl.fetch
27
48
  thimbl.print
28
- thimbl.post 'My first post'
49
+ thimbl.post 'My first post'
50
+ thimbl.push
51
+
52
+ ## TODO
53
+
54
+ * Shell script /bin/thimbl
55
+ * Thinking that the *plan_path* is not needed.
56
+ * Not save thimbl password, request for it in any *thimbl.push*
57
+ * Support *simbolize* hash keys
58
+ * In the Thimbl::Command.setup ask for the rest of the configuration options *bio*, *mobile*, ...
59
+ * thimbl.unfollow
60
+ * ERROR: If finger respond empty Plan
61
+ * ERROR: the message format is without *address* key.
data/Rakefile CHANGED
@@ -2,12 +2,12 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('thimbl', '0.0.1') do |p|
5
+ Echoe.new('thimbl', '0.0.2') do |p|
6
6
  p.description = "Small client for the distributed microbloging protocol: [thimbl](http://www.thimbl.net/)"
7
7
  p.url = "http://github.com/fguillen/ThimblClient"
8
8
  p.author = "Fernando Guillen"
9
9
  p.email = "fguillen.mail@gmail.com"
10
10
  p.ignore_pattern = ['etc/*']
11
- p.development_dependencies = ['mocha', 'ruby-debug']
12
- p.runtime_dependencies = []
11
+ p.development_dependencies = ['mocha', 'ruby-debug', 'delorean']
12
+ p.runtime_dependencies = ['json', 'net-scp', 'fileutils']
13
13
  end
data/bin/thimbl ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Use:
4
+ # thimbl setup ~/thimbl_plan ~/thimbl_cache 'user@thimblserver.com', 'thimblpass'
5
+ # thimbl follow 'dk' 'dk@telekommunisten.org'
6
+ # thimbl fetch
7
+ # thimbl print
8
+ # thimbl post "My first message :)"
9
+ # thimbl push
10
+
11
+ begin
12
+ require 'thimbl'
13
+ rescue LoadError
14
+ require 'rubygems'
15
+ require 'thimbl'
16
+ end
17
+
18
+ if ARGV.empty?
19
+ puts "use: $ thimbl <command>"
20
+ exit 1
21
+ end
22
+
23
+ begin
24
+ case ARGV[0]
25
+ when 'setup'; Thimbl::Command.setup( *ARGV[1..4] ); puts "setup completed"
26
+ when 'print'; puts Thimbl::Command.print
27
+ when 'fetch'; Thimbl::Command.fetch; puts "fecth completed"
28
+ when 'post'; Thimbl::Command.post ARGV[1]; puts "post completed"
29
+ when 'push'; Thimbl::Command.push; puts "push completed"
30
+ when 'follow'; Thimbl::Command.follow( ARGV[1], ARGV[2] ); puts "follow completed"
31
+ else
32
+ puts "command not valid '#{ARGV[0]}'"
33
+ end
34
+ rescue ArgumentError => e
35
+ puts e.message
36
+ end
data/lib/thimbl.rb CHANGED
@@ -1,125 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'json'
3
- require "#{File.dirname(__FILE__)}/finger"
4
-
5
- class Thimbl
6
- attr_reader :plan_path, :cache_path, :data, :address
7
-
8
- def initialize( plan_path, cache_path )
9
- @plan_path = plan_path
10
- @cache_path = cache_path
11
- @data = nil
12
- @address = nil
13
- end
14
-
15
- def setup( opts = {} )
16
- opts = {
17
- :bio => 'bio',
18
- :website => 'website',
19
- :mobile => 'mobile',
20
- :email => 'email',
21
- :address => 'address',
22
- :name => 'name'
23
- }.merge( opts )
24
-
25
- @data = {
26
- 'me' => opts[:address],
27
- 'plans' => {
28
- opts[:address] => {
29
- 'name' => opts[:name],
30
- 'bio' => opts[:bio],
31
- 'properties' => {
32
- 'email' => opts[:email],
33
- 'mobile' => opts[:mobile],
34
- 'website' => opts[:website]
35
- },
36
- 'following' => [],
37
- 'messages' => [],
38
- 'replies' => {}
39
- }
40
- }
41
- }
42
-
43
- @address = opts[:address]
44
-
45
- save_data
46
-
47
- return self
48
- end
49
-
50
- def post( text )
51
- load_data
52
-
53
- message = {
54
- :address => address,
55
- :time => Time.now.strftime('%Y%m%d%H%M%S'),
56
- :text => text
57
- }
58
-
59
- data['plans'][address]['messages'] << message
60
- save_data
61
-
62
- return self
63
- end
64
-
65
- def follow( follow_nick, follow_address )
66
- load_data
67
- data['plans'][address]['following'] << { :nick => follow_nick, :address => follow_address }
68
- save_data
69
-
70
- return self
71
- end
72
-
73
- def fetch
74
- load_data
75
-
76
- following.map { |f| f['address'] }.each do |followed_address|
77
- address_finger = Finger.run followed_address
78
- address_plan = address_finger.match(/Plan:\s*(.*)/m)[1].gsub("\n",'')
79
- data['plans'][followed_address] = JSON.load( address_plan )
80
- end
81
-
82
- save_data
83
-
84
- return self
85
- end
86
-
87
- def print
88
- load_data
89
-
90
- result = ""
91
- messages.each do |message|
92
- result += Thimbl.parse_time( message['time'] ).strftime( '%Y-%m-%d %H:%M:%S' )
93
- result += " #{message['address']}"
94
- result += " > #{message['text']}"
95
- result += "\n"
96
- end
97
-
98
- return result
99
- end
100
-
101
- def load_data
102
- @data = JSON.load( File.read cache_path )
103
- @address = data['me']
104
- end
105
-
106
- def save_data
107
- File.open( cache_path, 'w' ) { |f| f.write data.to_json }
108
- File.open( plan_path, 'w' ) { |f| f.write data['plans'][address].to_json }
109
- end
110
-
111
- def following
112
- data['plans'][address]['following']
113
- end
114
-
115
- def messages
116
- _messages = data['plans'].values.map { |e| e['messages'] }.flatten
117
- _messages = _messages.sort { |a,b| a['time'] <=> b['time'] }
118
-
119
- return _messages
120
- end
121
-
122
- def self.parse_time( time )
123
- Time.utc( time[0,4], time[4,2], time[6,2], time[8,2], time[10,2], time[12,2] )
124
- end
125
- end
3
+ require 'net/scp'
4
+ require 'fileutils'
5
+ require "#{File.dirname(__FILE__)}/thimbl/base"
6
+ require "#{File.dirname(__FILE__)}/thimbl/command"
7
+ require "#{File.dirname(__FILE__)}/thimbl/finger"
@@ -0,0 +1,223 @@
1
+ # Thimbl ruby client
2
+ #
3
+ # Author: fernandoguillen.info
4
+ #
5
+ # Code: https://github.com/fguillen/ThimblClient
6
+ #
7
+ # Use:
8
+ # require 'rubygems'
9
+ # require 'thimbl'
10
+ # thimbl =
11
+ # Thimbl::Base.new(
12
+ # :plan_path => '/tmp/plan',
13
+ # :cache_path => '/tmp/thimbl_cache',
14
+ # :user => 'fguillen@thimblserver.com'
15
+ # :password => 'my_thimblserver_password'
16
+ # )
17
+ # thimbl.setup(
18
+ # :bio => 'my bio',
19
+ # :website => 'my website',
20
+ # :mobile => 'my mobile',
21
+ # :email => 'my email',
22
+ # :address => 'my address',
23
+ # :name => 'my name'
24
+ # )
25
+ # thimbl.follow 'dk', 'dk@telekommunisten.org'
26
+ # thimbl.fetch
27
+ # thimbl.print
28
+ # thimbl.post 'My first post'
29
+ #
30
+ module Thimbl
31
+ class Base
32
+ attr_reader :plan_path, :cache_path, :data, :address, :user, :password
33
+
34
+ # Initialize the thimbl client.
35
+ #
36
+ # Use:
37
+ # Thimbl.new(
38
+ # :plan_path => <path to the plan file>,
39
+ # :cache_path => <path to the cache file>
40
+ # :user => <the user@domain>,
41
+ # :password => <the user password>
42
+ # )
43
+ #
44
+ def initialize( opts = {} )
45
+ @plan_path = opts['plan_path']
46
+ @cache_path = opts['cache_path']
47
+ @user = opts['user']
48
+ @password = opts['password']
49
+
50
+ @data = nil
51
+ @address = nil
52
+ end
53
+
54
+ # Setup a new configuration, the execution of this method
55
+ # will delete any thing in the `thimbl.plan_path` file and `thimbl.cache_path` file.
56
+ #
57
+ # Use:
58
+ # thimbl.setup(
59
+ # :bio => 'bio',
60
+ # :website => 'website',
61
+ # :mobile => 'mobile',
62
+ # :email => 'email',
63
+ # :address => 'address',
64
+ # :name => 'name'
65
+ # )
66
+ #
67
+ def setup( opts = {} )
68
+ opts = {
69
+ 'bio' => 'bio',
70
+ 'website' => 'website',
71
+ 'mobile' => 'mobile',
72
+ 'email' => 'email',
73
+ 'address' => 'address',
74
+ 'name' => 'name'
75
+ }.merge( opts )
76
+
77
+ @data = {
78
+ 'me' => opts['address'],
79
+ 'plans' => {
80
+ opts['address'] => {
81
+ 'name' => opts['name'],
82
+ 'bio' => opts['bio'],
83
+ 'properties' => {
84
+ 'email' => opts['email'],
85
+ 'mobile' => opts['mobile'],
86
+ 'website' => opts['website']
87
+ },
88
+ 'following' => [],
89
+ 'messages' => [],
90
+ 'replies' => {}
91
+ }
92
+ }
93
+ }
94
+
95
+ @address = opts['address']
96
+
97
+ save_data
98
+ end
99
+
100
+ # Post a new message in your time-line.
101
+ #
102
+ # Use:
103
+ # thimbl.post <message>
104
+ #
105
+ # To publish your comment you have to call:
106
+ # thimbl.push
107
+ #
108
+ def post( text )
109
+ message = {
110
+ 'address' => address,
111
+ 'time' => Time.now.strftime('%Y%m%d%H%M%S'),
112
+ 'text' => text
113
+ }
114
+
115
+ data['plans'][address]['messages'] << message
116
+ save_data
117
+ end
118
+
119
+ # Add a new user to follow
120
+ #
121
+ # Use:
122
+ # thimbl.follow 'nick', 'address'
123
+ #
124
+ # To publish your following users you have to call:
125
+ # thimbl.push
126
+ #
127
+ def follow( follow_nick, follow_address )
128
+ data['plans'][address]['following'] << { 'nick' => follow_nick, 'address' => follow_address }
129
+ save_data
130
+ end
131
+
132
+ # Fetch all the info and timelines of all the users you are following.
133
+ #
134
+ # Use:
135
+ # thimbl.fetch
136
+ #
137
+ def fetch
138
+ following.map { |f| f['address'] }.each do |followed_address|
139
+ address_finger = Thimbl::Finger.run followed_address
140
+ address_plan = address_finger.match(/Plan:\s*(.*)/m)[1].gsub("\\\n",'')
141
+ data['plans'][followed_address] = JSON.load( address_plan )
142
+ end
143
+
144
+ save_data
145
+ end
146
+
147
+ # Print every message of you and all the users you are following.
148
+ #
149
+ # Use:
150
+ # thimbl.print
151
+ # The method doesn't print anything by it self. It just returns an string
152
+ # with all the comments.
153
+ #
154
+ def print
155
+ result = ""
156
+ messages.each do |message|
157
+ result += Thimbl::Base.parse_time( message['time'] ).strftime( '%Y-%m-%d %H:%M:%S' )
158
+ result += " #{message['address']}"
159
+ result += " > #{message['text']}"
160
+ result += "\n"
161
+ end
162
+
163
+ return result
164
+ end
165
+
166
+ # Send your actual `plan` file to your server
167
+ #
168
+ # Use:
169
+ # thimbl.push
170
+ #
171
+ def push
172
+ Net::SCP.start( user.split('@')[1], user.split('@')[0], :password => password ) do |scp|
173
+ scp.upload!( plan_path, ".plan" )
174
+ end
175
+ end
176
+
177
+ # Charge into the `thimbl` object all the data into your `cache` file.
178
+ # Use:
179
+ # thimbl.load_data
180
+ #
181
+ def load_data
182
+ @data = JSON.load( File.read cache_path )
183
+ @address = data['me']
184
+ end
185
+
186
+ # Save all the data into the `thimbl` objecto into your `cache` file and
187
+ # `plan` file.
188
+ #
189
+ # Use:
190
+ # thimbl.save_data
191
+ #
192
+ def save_data
193
+ File.open( cache_path, 'w' ) { |f| f.write data.to_json }
194
+ File.open( plan_path, 'w' ) { |f| f.write data['plans'][address].to_json }
195
+ end
196
+
197
+ # Returns all the info about the users you are following.
198
+ #
199
+ # Use:
200
+ # thimbl.following
201
+ #
202
+ def following
203
+ data['plans'][address]['following']
204
+ end
205
+
206
+ # Returns all the messages of you and all the users you are following
207
+ # in a chronologic order into a json format.
208
+ #
209
+ # Use:
210
+ # thimbl.messages
211
+ #
212
+ def messages
213
+ _messages = data['plans'].values.map { |e| e['messages'] }.flatten
214
+ _messages = _messages.sort { |a,b| a['time'] <=> b['time'] }
215
+
216
+ return _messages
217
+ end
218
+
219
+ def self.parse_time( time )
220
+ Time.utc( time[0,4], time[4,2], time[6,2], time[8,2], time[10,2], time[12,2] )
221
+ end
222
+ end
223
+ end