TokiCLI 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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 24126edaca561eab0623a449445132dddf6697a0
4
+ data.tar.gz: bec8ef8903fd53c79b8ef96696dc04fde69e9e7b
5
+ SHA512:
6
+ metadata.gz: 985a22eda651b23467d18db8e7198edd24c5454275a09958e31b4d38a74f9a4d44031e30033302dd7cba00a3485b0b7301470464f605ce94170d2e1f7a8ab2f3
7
+ data.tar.gz: 8168f8fa325678e6e4d332476ee0d889a9819bbcf9a917e0cf89d7442b29c5295350f049a0f1ad5f19168f69193fb723df3ff0354767d00dab3247970d71dbac
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ token
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in TokiCLI.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Eric Dejonckheere
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,13 @@
1
+ # TokiCLI
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ $ gem install TokiCLI
8
+
9
+ ## Usage
10
+
11
+ TODO: Write usage instructions here
12
+
13
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'TokiCLI/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "TokiCLI"
8
+ spec.version = TokiCLI::VERSION
9
+ spec.authors = ["Eric Dejonckheere"]
10
+ spec.email = ["eric@aya.io"]
11
+ spec.summary = %q{Toki command-line client}
12
+ spec.description = %q{Toki command-line client: read your Toki data from the local database or from the App.net backup channel}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.required_ruby_version = '>= 1.9.3'
22
+
23
+ spec.add_dependency "thor", ">= 0.18"
24
+ spec.add_dependency "rest-client", ">= 1.6"
25
+ spec.add_dependency "amalgalite", ">= 1.3"
26
+ spec.add_dependency "terminal-table", ">= 1.4"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.6"
29
+ spec.add_development_dependency "rake"
30
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # Toki command-line client
4
+ # Author: Eric Dejonckheere (http://app.net/ericd)
5
+ # Toki by: Keita Kobayashi (http://app.net/keita)
6
+
7
+ $PROGRAM_NAME = 'toki'
8
+ require_relative '../lib/TokiCLI'
9
+
10
+ TokiCLI::App.start ARGV
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ require 'ostruct'
3
+ require 'thor'
4
+ require 'amalgalite'
5
+ require 'terminal-table/import'
6
+ require_relative "TokiCLI/version"
7
+ require_relative "TokiCLI/app"
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class App < Thor
4
+ package_name "TokiCLI"
5
+ %w{get_messages search_messages get_channels module status view}.each {|r| require_relative "#{r}"}
6
+
7
+ desc "total", "Shows the total usage of all apps"
8
+ option :adn, aliases: '-a', type: :boolean, desc: 'Select ADN channel as source (toki total -a)'
9
+ def total
10
+ if options[:adn]
11
+ toki = total_adn
12
+ else
13
+ toki = total_db
14
+ end
15
+ get_total(toki, options)
16
+ end
17
+
18
+ desc "auth", "Input your App.net token for authorization"
19
+ def auth
20
+ puts Status.paste_token
21
+ token = STDIN.gets.chomp!
22
+ unless token.nil?
23
+ save_token(token)
24
+ else
25
+ abort(Status.no_token)
26
+ end
27
+ puts Status.done
28
+ end
29
+
30
+ desc "log APP", "Shows the complete log for an app"
31
+ option :adn, aliases: '-a', type: :boolean, desc: 'Select ADN channel as source (toki total -a)'
32
+ def log(*args)
33
+ abort(Status.specify_name) if args.empty?
34
+ if options[:adn]
35
+ toki = total_adn
36
+ else
37
+ toki = total_db
38
+ end
39
+ asked = args[0]
40
+ synced = toki.get_content(options)
41
+ app_data = toki.get_app(asked, synced)
42
+ v = TokiCLI::View.new
43
+ puts v.app_table(asked, app_data)
44
+ puts "\n"
45
+ end
46
+
47
+ private
48
+
49
+ def total_adn
50
+ clear
51
+ puts Status.get_all
52
+ init_toki_adn
53
+ end
54
+
55
+ def total_db
56
+ clear
57
+ puts "getting data from db\n"
58
+ init_toki_db
59
+ end
60
+
61
+ def get_total(toki, options)
62
+ begin
63
+ apps = get_all(toki, options)
64
+ rescue Interrupt
65
+ puts Status.canceled
66
+ exit
67
+ rescue => e
68
+ puts Status.error(e)
69
+ exit
70
+ end
71
+ clear
72
+ puts TokiCLI::View.new.total_table(apps)
73
+ puts "\n"
74
+ end
75
+
76
+ def init_toki_db
77
+ TokiCLI::Toki.new(nil, nil)
78
+ end
79
+
80
+ def init_toki_adn(channel_id = get_channel_id)
81
+ TokiCLI::Toki.new("#{get_token}", channel_id)
82
+ end
83
+
84
+ def save_token(token)
85
+ File.write(Dir.home + '/.toki_token', token)
86
+ end
87
+ def get_token
88
+ if File.exist?(Dir.home + '/.toki_token')
89
+ File.read(Dir.home + '/.toki_token').chomp
90
+ else
91
+ abort Status.run_auth
92
+ end
93
+ end
94
+ def get_channel_id #TODO return ch['counts']['messages'] too
95
+ channels = ADNChannels::GetChannels.new(get_token).get_channels
96
+ channel_id = ''
97
+ channels.each do |ch|
98
+ if ch['type'] == 'us.kkob.toki.sync-b'
99
+ channel_id = ch['id']
100
+ break
101
+ end
102
+ end
103
+ return channel_id.to_i unless channel_id == ''
104
+ puts Status.no_channel
105
+ exit
106
+ end
107
+ def clear
108
+ puts "\e[H\e[2J"
109
+ end
110
+ def get_all(t, options)
111
+ t.all_data(t.get_content(options))
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,22 @@
1
+ require 'json'
2
+ require 'rest_client'
3
+ module ADNChannels
4
+ class GetChannels
5
+ def initialize(token)
6
+ @base_url = 'http://api.app.net'
7
+ @token = token
8
+ end
9
+ def get_channels
10
+ args = {:count => 200, :before_id => nil}
11
+ channels = []
12
+ loop do
13
+ @url = "#{@base_url}/users/me/channels?access_token=#{@token}&include_machine=1&include_message_annotations=1&include_deleted=0&include_html=0&count=#{args[:count]}&before_id=#{args[:before_id]}"
14
+ resp = JSON.parse(RestClient.get(@url))
15
+ resp['data'].each { |m| channels << m }
16
+ break unless resp['meta']['more']
17
+ args = {:count => 200, :before_id => resp['meta']['min_id']}
18
+ end
19
+ channels
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+ require 'rest_client'
3
+ module ADNChannels
4
+ class GetMessages
5
+ def initialize(token)
6
+ @base_url = 'http://api.app.net'
7
+ @token = token
8
+ end
9
+ def get_messages(channel_id)
10
+ args = {:count => 200, :before_id => nil}
11
+ messages = []
12
+ @index = 1
13
+ puts "Downloading synced objects (~1MB/page):\n\n"
14
+ loop do
15
+ puts "--Downloading from page #{@index}...\n"
16
+ @url = "#{@base_url}/channels/#{channel_id}/messages?access_token=#{@token}&include_machine=1&include_message_annotations=1&include_deleted=0&include_html=0&count=#{args[:count]}&before_id=#{args[:before_id]}"
17
+ begin
18
+ data = RestClient.get(@url)
19
+ rescue Interrupt
20
+ puts TokiCLI::Status.canceled
21
+ exit
22
+ end
23
+ resp = JSON.parse(data)
24
+ resp['data'].each { |m| messages << m }
25
+ break unless resp['meta']['more']
26
+ @index += 1
27
+ args = {:count => 200, :before_id => resp['meta']['min_id']}
28
+ end
29
+ messages
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,142 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class Toki
4
+ def initialize(token, channel_id)
5
+ @token = token
6
+ @channel_id = channel_id
7
+ end
8
+ def get_content(options)
9
+ synced = []
10
+ if options[:adn]
11
+ messages = get_adn_data
12
+ messages.reverse.each do |obj|
13
+ synced << make_obj_from_adn(obj)
14
+ end
15
+ else
16
+ content = get_db_data
17
+ content.each do |obj|
18
+ synced << make_obj_from_db(obj)
19
+ end
20
+ end
21
+ synced
22
+ end
23
+ def get_app(app, synced)
24
+ name_regex = /#{app.downcase}/
25
+ app_data = {}
26
+ totals = {}
27
+ synced.each do |obj|
28
+ next unless obj.app[:name].downcase =~ name_regex
29
+ unless totals[:app].nil?
30
+ totals[:app] = totals[:app] + obj.app[:total]
31
+ else
32
+ totals[:app] = obj.app[:total]
33
+ end
34
+ human = epoch_to_human(obj.app[:total])
35
+ app_data[obj.msg[:id]] = {
36
+ from: Time.at(obj.app[:active_from]).strftime("%Y/%m/%d %Hh:%Mm:%Ss"),
37
+ to: Time.at(obj.app[:active_to]).strftime("%Y/%m/%d %Hh:%Mm:%Ss"),
38
+ duration: "#{human[:hours]}h #{human[:minutes]}m #{human[:seconds]}s"
39
+ }
40
+ end
41
+ human = epoch_to_human(totals[:app])
42
+ app_data['total'] = "#{human[:hours]}h #{human[:minutes]}m #{human[:seconds]}s"
43
+ app_data
44
+ end
45
+ def all_data(synced)
46
+ totals = {}
47
+ synced.each do |obj|
48
+ unless totals[obj.app[:name]].nil?
49
+ totals[obj.app[:name]] = totals[obj.app[:name]] + obj.app[:total]
50
+ else
51
+ totals[obj.app[:name]] = obj.app[:total]
52
+ end
53
+ end
54
+ bundles = {}
55
+ sorted = totals.sort_by{ |k,v| v }
56
+ sorted.each do |name, total|
57
+ human = epoch_to_human(total)
58
+ if human[:hours] < 1
59
+ bundles[name] = "#{human[:minutes]}m #{human[:seconds]}s"
60
+ else
61
+ bundles[name] = "#{human[:hours]}h #{human[:minutes]}m #{human[:seconds]}s"
62
+ end
63
+ end
64
+ bundles
65
+ end
66
+
67
+ private
68
+
69
+ def epoch_to_human(epoch)
70
+ hours = epoch / 3600
71
+ minutes = (epoch / 60 - hours * 60)
72
+ seconds = (epoch - (minutes * 60 + hours * 3600))
73
+ {hours: hours, minutes: minutes, seconds: seconds}
74
+ end
75
+
76
+ def get_adn_data
77
+ channels = ADNChannels::GetMessages.new(@token) #ericd
78
+ channels.get_messages(@channel_id)
79
+ end
80
+
81
+ def get_db_data
82
+ db = open_db
83
+ data = db.execute("SELECT * FROM KKAppActivity")
84
+ data
85
+ end
86
+
87
+
88
+
89
+ def open_db
90
+ tmp_path = "#{Dir.home}/temp/toki/"
91
+ db_path = "#{Dir.home}/Library/Containers/us.kkob.Toki/Data/Documents/toki_data.sqlite3"
92
+ FileUtils.mkdir_p(tmp_path)
93
+ FileUtils.copy(db_path, "#{tmp_path}/toki_data.bak")
94
+ Amalgalite::Database.new(db_path)
95
+ end
96
+
97
+ def make_obj_from_adn(obj)
98
+ msg = {}
99
+ usr = {}
100
+ app = {}
101
+ d = obj['annotations'][0]['value']['d']
102
+ msg[:id] = obj['id']
103
+ msg[:thread] = obj['thread_id']
104
+ msg[:date] = parsed_date obj['created_at']
105
+ usr[:username] = obj['user']['username']
106
+ usr[:name] = obj['user']['name']
107
+ usr[:id] = obj['user']['id']
108
+ app[:id] = d['id']
109
+ app[:uuid] = d['UUID']
110
+ app[:name] = d['bundleIdentifier']
111
+ app[:active_to] = d['activeTo']
112
+ app[:active_from] = d['activeFrom']
113
+ app[:total] = d['totalSeconds']
114
+ OpenStruct.new(app: app, msg: msg, usr: usr)
115
+ end
116
+
117
+ def make_obj_from_db(obj)
118
+ # content is an array:
119
+ # id (INTEGER) 0, bundleIdentifier (VARCHAR) 1, activeFrom (INTEGER) 2, activeTo (INTEGER) 3, totalSeconds (INTEGER) 4, UUID (VARCHAR) 5, synced (INTEGER) 6, availableToSync (INTEGER) 7
120
+ msg = {}
121
+ usr = {}
122
+ app = {}
123
+ msg[:id] = rand(100000000)
124
+ msg[:thread] = msg[:id]
125
+ msg[:date] = Time.now
126
+ usr[:username] = ENV['USERNAME']
127
+ usr[:name] = usr[:username]
128
+ usr[:id] = obj[5]
129
+ app[:id] = obj[0]
130
+ app[:uuid] = obj[5]
131
+ app[:name] = obj[1]
132
+ app[:active_to] = obj[3]
133
+ app[:active_from] = obj[2]
134
+ app[:total] = obj[4]
135
+ OpenStruct.new(app: app, msg: msg, usr: usr)
136
+ end
137
+
138
+ def parsed_date(string)
139
+ "#{string[0...10]} #{string[11...19]}"
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,23 @@
1
+ require 'json'
2
+ require 'rest_client'
3
+ module ADNChannels
4
+ class SearchMessages
5
+ def initialize(token)
6
+ @base_url = 'http://api.app.net'
7
+ @token = token
8
+ end
9
+ def search_annotation(channel_id, query)
10
+ args = {:count => 200, :before_id => nil}
11
+ messages = []
12
+ loop do
13
+ @url = "#{@base_url}/channels/messages/search?query=#{query}&channel_ids=#{channel_id}&access_token=#{@token}&include_machine=1&include_message_annotations=1&include_deleted=0&count=#{args[:count]}&before_id=#{args[:before_id]}"
14
+ resp = JSON.parse(RestClient.get(@url))
15
+ resp['data'].each { |m| messages << m }
16
+ break unless resp['meta']['more']
17
+ args = {:count => 200, :before_id => resp['meta']['min_id']}
18
+ end
19
+ messages
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class Status
4
+ def self.get_all
5
+ "Toki_CLI is crawling your Toki App.net channel to get your data.\nIt could take a while, please be patient.\n\n"
6
+ end
7
+ def self.canceled
8
+ "\n\nCanceled.\n\n"
9
+ end
10
+ def self.error(e)
11
+ "\n\nStopped. Error: \n#{e}\n\n"
12
+ end
13
+ def self.no_channel
14
+ "\n\nCan't find your Toki App.net channel, sorry.\n\n"
15
+ end
16
+ def self.paste_token
17
+ "\nPlease paste your App.net token:\n\n"
18
+ end
19
+ def self.no_token
20
+ "\nOops, I didn't get the token. Please try again.\n"
21
+ end
22
+ def self.done
23
+ "\nDone.\n"
24
+ end
25
+ def self.specify_name
26
+ "\nPlease specify the name of the app (or part of it).\n\n"
27
+ end
28
+ def self.run_auth
29
+ "\nPlease run `toki auth` first.\n\n"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module TokiCLI
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class View
4
+ def total_table(list)
5
+ table = init_table
6
+ table.title = "Your apps monitored by Toki"
7
+ list.each do |k,v|
8
+ table << ["#{k}", "#{v}"]
9
+ end
10
+ table
11
+ end
12
+ def app_table(asked, app_data)
13
+ table = init_table
14
+ table.title = "Toki time tracking for '#{asked}'"
15
+ table.headings = ['From', 'To', 'Duration']
16
+ @index = 0
17
+ @length = app_data.length - 1
18
+ app_data.each do |id, log|
19
+ if id == 'total'
20
+ @total = log
21
+ next
22
+ end
23
+ @index += 1
24
+ table << ["#{log[:from]}", "#{log[:to]}", "#{log[:duration]}"]
25
+ table << :separator unless @index == @length
26
+ end
27
+ table << :separator
28
+ table << [{ :value => "Total: #{@total}", :colspan => 3, :alignment => :center }]
29
+ table
30
+ end
31
+
32
+ private
33
+
34
+ def init_table
35
+ Terminal::Table.new do |t|
36
+ t.style = { :width => 75 }
37
+ end
38
+ end
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: TokiCLI
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eric Dejonckheere
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0.18'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0.18'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: amalgalite
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: terminal-table
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: 'Toki command-line client: read your Toki data from the local database
98
+ or from the App.net backup channel'
99
+ email:
100
+ - eric@aya.io
101
+ executables:
102
+ - toki
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - TokiCLI.gemspec
112
+ - bin/toki
113
+ - lib/TokiCLI.rb
114
+ - lib/TokiCLI/app.rb
115
+ - lib/TokiCLI/get_channels.rb
116
+ - lib/TokiCLI/get_messages.rb
117
+ - lib/TokiCLI/module.rb
118
+ - lib/TokiCLI/search_messages.rb
119
+ - lib/TokiCLI/status.rb
120
+ - lib/TokiCLI/version.rb
121
+ - lib/TokiCLI/view.rb
122
+ homepage: ''
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 1.9.3
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.2.2
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Toki command-line client
146
+ test_files: []
147
+ has_rdoc: