twat 0.6.3 → 0.9.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 (71) hide show
  1. data/.rvmrc +1 -1
  2. data/.travis.yml +6 -0
  3. data/Gemfile +1 -4
  4. data/Gemfile.lock +43 -23
  5. data/Gemfile.travis +12 -0
  6. data/Rakefile +9 -0
  7. data/TODO +4 -1
  8. data/lib/twat.rb +30 -26
  9. data/lib/twat/argparse.rb +36 -79
  10. data/lib/twat/config.rb +22 -34
  11. data/lib/twat/endpoint.rb +11 -5
  12. data/lib/twat/endpoints/base.rb +39 -0
  13. data/lib/twat/endpoints/identica.rb +5 -1
  14. data/lib/twat/endpoints/twitter.rb +5 -1
  15. data/lib/twat/exceptions.rb +93 -46
  16. data/lib/twat/follow_mixin.rb +134 -0
  17. data/lib/twat/options.rb +28 -12
  18. data/lib/twat/subcommand.rb +34 -0
  19. data/lib/twat/subcommands/add.rb +17 -0
  20. data/lib/twat/subcommands/base.rb +122 -0
  21. data/lib/twat/subcommands/config.rb +15 -0
  22. data/lib/twat/subcommands/delete.rb +24 -0
  23. data/lib/twat/subcommands/finger.rb +23 -0
  24. data/lib/twat/subcommands/follow.rb +18 -0
  25. data/lib/twat/subcommands/follow_tag.rb +19 -0
  26. data/lib/twat/subcommands/list.rb +17 -0
  27. data/lib/twat/subcommands/mentions.rb +20 -0
  28. data/lib/twat/subcommands/set.rb +19 -0
  29. data/lib/twat/subcommands/track.rb +33 -0
  30. data/lib/twat/subcommands/update.rb +21 -0
  31. data/lib/twat/subcommands/update_config.rb +16 -0
  32. data/lib/twat/subcommands/version.rb +14 -0
  33. data/lib/twat/twatopt.rb +0 -0
  34. data/lib/twat/tweetstack.rb +38 -0
  35. data/lib/twat/version.rb +7 -0
  36. data/man/twat.1 +8 -5
  37. data/spec/argparse_spec.rb +48 -0
  38. data/spec/helpers/environment.rb +47 -0
  39. data/spec/helpers/fileutils.rb +18 -0
  40. data/spec/helpers/fixtures/core.rb +30 -0
  41. data/spec/helpers/fixtures/migrations.rb +13 -0
  42. data/spec/helpers/oauth.rb +15 -0
  43. data/spec/spec_helper.rb +13 -0
  44. data/spec/subcommands/add_spec.rb +61 -0
  45. data/spec/subcommands/config_spec.rb +13 -0
  46. data/spec/subcommands/delete_spec.rb +12 -0
  47. data/spec/subcommands/finger_spec.rb +41 -0
  48. data/spec/subcommands/follow_spec.rb +12 -0
  49. data/spec/subcommands/follow_tag_spec.rb +52 -0
  50. data/spec/subcommands/list_spec.rb +8 -0
  51. data/spec/subcommands/mentions_spec.rb +24 -0
  52. data/spec/subcommands/set_spec.rb +126 -0
  53. data/spec/subcommands/track_spec.rb +23 -0
  54. data/spec/subcommands/update_config_spec.rb +23 -0
  55. data/spec/subcommands/update_spec.rb +12 -0
  56. data/spec/subcommands/version_spec.rb +12 -0
  57. data/spec/twat_cli_spec.rb +102 -0
  58. data/spec/twat_spec.rb +12 -0
  59. data/twat.gemspec +6 -2
  60. metadata +135 -22
  61. data/lib/twat/actions.rb +0 -85
  62. data/lib/twat/actions/add.rb +0 -36
  63. data/lib/twat/actions/delete.rb +0 -14
  64. data/lib/twat/actions/follow.rb +0 -148
  65. data/lib/twat/actions/follow_user.rb +0 -11
  66. data/lib/twat/actions/setoption.rb +0 -14
  67. data/lib/twat/actions/show.rb +0 -12
  68. data/lib/twat/actions/tweet.rb +0 -14
  69. data/lib/twat/actions/updateconfig.rb +0 -9
  70. data/lib/twat/actions/user_feed.rb +0 -17
  71. data/lib/twat/actions/version.rb +0 -9
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm 1.9.3
1
+ rvm use 1.9.3
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ gemfile: Gemfile.travis
3
+ rvm:
4
+ # - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
data/Gemfile CHANGED
@@ -1,5 +1,2 @@
1
1
  source :rubygems
2
-
3
- gem "twitter"
4
- gem "oauth"
5
- gem "rack", '1.3.3'
2
+ gemspec
@@ -1,31 +1,51 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ twat (0.9.1)
5
+ oauth
6
+ readline-ng (>= 0.0.8)
7
+ twitter
8
+
1
9
  GEM
2
10
  remote: http://rubygems.org/
3
11
  specs:
4
- addressable (2.2.6)
5
- faraday (0.7.4)
6
- addressable (~> 2.2.6)
7
- multipart-post (~> 1.1.0)
8
- rack (>= 1.1.0, < 2)
9
- faraday_middleware (0.7.0)
10
- faraday (~> 0.7.3)
11
- hashie (1.1.0)
12
- multi_json (1.0.3)
13
- multi_xml (0.2.2)
14
- multipart-post (1.1.3)
15
- oauth (0.4.5)
16
- rack (1.3.2)
17
- simple_oauth (0.1.5)
18
- twitter (1.6.2)
19
- faraday (~> 0.7.4)
20
- faraday_middleware (~> 0.7.0)
21
- hashie (~> 1.1.0)
22
- multi_json (~> 1.0.0)
23
- multi_xml (~> 0.2.0)
24
- simple_oauth (~> 0.1.5)
12
+ activesupport (3.2.3)
13
+ i18n (~> 0.6)
14
+ multi_json (~> 1.0)
15
+ diff-lcs (1.1.3)
16
+ faraday (0.8.0)
17
+ multipart-post (~> 1.1)
18
+ i18n (0.6.0)
19
+ metaclass (0.0.1)
20
+ mktemp (0.0.1)
21
+ mocha (0.11.3)
22
+ metaclass (~> 0.0.1)
23
+ multi_json (1.3.2)
24
+ multipart-post (1.1.5)
25
+ oauth (0.4.6)
26
+ rake (0.9.2.2)
27
+ readline-ng (0.0.8)
28
+ rspec (2.9.0)
29
+ rspec-core (~> 2.9.0)
30
+ rspec-expectations (~> 2.9.0)
31
+ rspec-mocks (~> 2.9.0)
32
+ rspec-core (2.9.0)
33
+ rspec-expectations (2.9.1)
34
+ diff-lcs (~> 1.1.3)
35
+ rspec-mocks (2.9.0)
36
+ simple_oauth (0.1.7)
37
+ twitter (2.2.4)
38
+ activesupport (>= 2.3.9, < 4)
39
+ faraday (~> 0.8)
40
+ multi_json (~> 1.3)
41
+ simple_oauth (~> 0.1.6)
25
42
 
26
43
  PLATFORMS
27
44
  ruby
28
45
 
29
46
  DEPENDENCIES
30
- oauth
31
- twitter
47
+ mktemp
48
+ mocha
49
+ rake
50
+ rspec
51
+ twat!
@@ -0,0 +1,12 @@
1
+ source :rubygems
2
+
3
+ gem "twitter"
4
+ gem "oauth"
5
+ gem "readline-ng", ">= 0.0.4"
6
+ group :test do
7
+ gem "rake"
8
+ gem "mocha"
9
+ gem "rspec"
10
+ gem "mktemp"
11
+ end
12
+
@@ -0,0 +1,9 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.pattern = "spec/**/*_spec.rb"
6
+ end
7
+
8
+ desc 'Default: run specs'
9
+ task :default => :spec
data/TODO CHANGED
@@ -5,7 +5,6 @@ COLORS!
5
5
 
6
6
  Refactor tweet printing code, unify throughout
7
7
 
8
-
9
8
  TODO
10
9
  ====
11
10
 
@@ -45,6 +44,10 @@ Allow -f #hashtag to follow that hashtag instead of your newsfeed
45
44
 
46
45
  Seriously consider moving to subcommands
47
46
 
47
+ Still needs argv parsing for account etc
48
+
49
+ twat config to create the first account from scratch
50
+
48
51
  MOAR BACKENDS
49
52
  =============
50
53
 
@@ -5,18 +5,20 @@ require 'twitter'
5
5
  require 'yaml'
6
6
  require 'optparse'
7
7
  require 'oauth'
8
+ require 'readline-ng'
8
9
 
9
- %w[config exceptions argparse actions migration options endpoint].each do |filename|
10
+ %w[follow_mixin endpoint exceptions config argparse migration options
11
+ subcommand version tweetstack].each do |filename|
10
12
  require "twat/#{filename}"
11
13
  end
12
14
 
13
- %w[follow tweet add delete follow_user updateconfig setoption show user_feed version].each do |filename|
14
- require "twat/actions/#{filename}"
15
- end
16
-
17
15
  class String
18
16
  # TODO - It'd be nice to implement the colors support here, maybe even only
19
17
  # mix this in if it's enabled?
18
+ def black
19
+ "#{self}"
20
+ end
21
+
20
22
  def red
21
23
  "#{self}"
22
24
  end
@@ -44,33 +46,35 @@ class String
44
46
  def mentions?(name)
45
47
  return self.downcase.include?(name.to_s.downcase)
46
48
  end
47
- end
48
49
 
49
- module Twat
50
- VERSION_MAJOR = 0
51
- VERSION_MINOR = 6
52
- VERSION_PATCH = 3
53
-
54
- VERSION = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_PATCH}"
55
- class Twat
50
+ def colorise!
51
+ colorise_handles!
52
+ colorise_hashtags!
53
+ colorise_urls!
54
+ end
56
55
 
57
- include HandledExceptions
56
+ def colorise_handles!
57
+ self.gsub!(/@[a-z0-9_+-]+/i) { |s| s.cyan }
58
+ return self
59
+ end
58
60
 
59
- def cli_run
60
- # FIXME Handing in the opts like this feels dirty
61
- with_handled_exceptions(ArgParse.new) do |opts|
62
- if opts[:account] && opts[:action] != :add
63
- config.account = opts[:account]
64
- end
61
+ def colorise_hashtags!
62
+ self.gsub!(/#[a-z0-9_+-]+/i) { |s| s.cyan }
63
+ return self
64
+ end
65
65
 
66
- require 'readline-ng'
67
- actor = Actions.new
66
+ def colorise_urls!
67
+ self.gsub!(%r{https?://[a-z0-9./_+-]+}i) { |s| s.black }
68
+ return self
69
+ end
70
+ end
68
71
 
72
+ module Twat
73
+ class Twat
69
74
 
70
- actor.config = config
71
- actor.opts = opts
72
- actor.send(opts.options[:action])
73
- end
75
+ def cli_run
76
+ # FIXME exception handling is gone for now
77
+ Subcommand.run
74
78
  end
75
79
  end
76
80
  end
@@ -1,10 +1,36 @@
1
1
  module Twat
2
- REQUIRED = []
3
- MSG_REQUIRED = [:tweet]
2
+ class ArgWrapper
3
+ def initialize(data)
4
+ @data = data
5
+ end
4
6
 
5
- class ArgParse
7
+ def method_missing(sym)
8
+ @data[sym]
9
+ end
10
+ end
6
11
 
12
+ class Args
7
13
  # TODO delegate specifically instead of shimming everything?
14
+ # TODO Twat::Subcommands.COMMANDS needs to be parsed and dumped
15
+
16
+ def initialize
17
+ # XXX What the shit...
18
+ getopts
19
+ end
20
+
21
+ def method_missing(sym)
22
+ @options[sym]
23
+ end
24
+
25
+ def [](key)
26
+ @options[key]
27
+ end
28
+
29
+ def include?(key)
30
+ @options.include?(key)
31
+ end
32
+
33
+ private
8
34
 
9
35
  def usage(additional=nil)
10
36
  puts additional if additional
@@ -14,100 +40,31 @@ module Twat
14
40
 
15
41
  def getopts
16
42
  options = Hash.new
17
- options[:count] = 1
18
43
  @optparser = OptionParser.new do |opts|
19
44
  opts.banner = "Usage: twat <tweet>"
20
45
 
21
46
  opts.on('-n', '--account ACCOUNT', 'Use ACCOUNT (or default)') do |acct| #{{{ --account ACCOUNT
22
47
  options[:account] = acct.to_sym
23
48
  end # }}}
24
- opts.on('-a', '--add ACCOUNT', 'Configure and authorise ACCOUNT') do |acct| #{{{ --add ACCOUNT
25
- options[:account] = acct.to_sym
26
- options[:action] = :add
27
- end #}}}
28
- opts.on('--follow-user USER', 'Follow USER on twitter') do |user| #{{{ --follow-user USER
29
- options[:action] = :follow_user
30
- options[:user] = user
31
- end #}}}
32
- opts.on('--endpoint ENDPOINT', 'Specify a different endpoint for use with --add') do |endpoint| #{{{ --add ACCOUNT
49
+ opts.on('--endpoint ENDPOINT', 'Specify a different endpoint for use with add or config') do |endpoint| #{{{ --add ACCOUNT
33
50
  options[:endpoint] = endpoint.to_sym
34
51
  end #}}}
35
- opts.on('-d', '--delete ACCOUNT', 'Delete ACCOUNT') do |acct| #{{{ --delete ACCOUNT
36
- options[:account] = acct.to_sym
37
- options[:action] = :delete
38
- end #}}}
39
52
  opts.on('-h', '--help', 'Display this screen') do #{{{ --help
40
53
  puts opts
41
54
  exit
42
55
  end #}}}
43
- opts.on('-l', '--list [COUNT]', 'Display [count] tweets from your newsfeed') do |count| #{{{ --list ACCOUNT
44
- options[:count] = count || 10
45
- options[:action] ||= :show
46
- end #}}}
47
- opts.on('-f', '--follow', 'Display tweets from your newsfeed indefinitely') do #{{{ --follow
48
- options[:action] = :follow
49
- end #}}}
50
56
  opts.on('-v', '--version', 'Display version info') do #{{{ --version
51
- options[:action] = :version
52
- end #}}}
53
- opts.on('-u', '--user [USER]', 'Display current status for USER (Defaults to your default account)') do |user| #{{{ --user USER
54
- options[:user] = (user || :default)
55
- options[:action] = :user_feed
56
- end #}}}
57
- opts.on("--set OPTION=VALUE", 'Set OPTION to VALUE') do |optval| #{{{ --set OPTION=VALUE
58
- options[:action] = :setoption
59
- options[:optval] = optval
60
- end #}}}
61
- opts.on("--update-config", "Update config to latest version") do #{{{ --update-config
62
- options[:action] = :updateconfig
57
+ # FIXME, this is /bad/
58
+ puts "twat #{::Twat::VERSION}"
59
+ exit
63
60
  end #}}}
64
61
  end
65
62
  @optparser.parse!
66
- # {{{ Validation ---
67
- # Default action is to send a tweet
68
- options[:action] ||= :tweet
69
-
70
- # Only specify an endpoint when adding accounts
71
- if options[:endpoint]
72
- usage unless options[:action] == :add
73
- end
74
- # Similarly, default endpoint to twitter when we do add
75
- if options[:action] == :add
76
- options[:endpoint] ||= :twitter
77
- end
78
-
79
- REQUIRED.each do |req|
80
- usage unless options[req]
81
- end
82
- if MSG_REQUIRED.include?(options[:action])
83
- options[:msg] = msg
84
- end
85
- # }}} Validation End ---
86
- options
87
- end
88
-
89
- def msg
90
- usage unless ARGV.length > 0
91
- ARGV.join(" ")
92
- end
93
-
94
- def [](key)
95
- options[key]
96
- end
97
63
 
98
- def include?(key)
99
- options.include?(key)
100
- end
64
+ # Only makes sense for add, but doesn't hurt anything else
65
+ options[:endpoint] ||= :twitter
101
66
 
102
- def options
103
- begin
104
- @configthingfucken ||= getopts
105
- # FIXME, actually do something smart, not yell and barf
106
- rescue OptionParser::InvalidOption
107
- usage "Unknown option"
108
- rescue OptionParser::MissingArgument
109
- usage "Missing argument"
110
- end
67
+ @options = options
111
68
  end
112
69
 
113
70
  end
@@ -1,21 +1,19 @@
1
1
  module Twat
2
- class Twat
3
- def configure(&block)
4
- yield config
2
+ class Config
5
3
 
6
- # If I understand correctly, I can check over what's
7
- # happened here?
8
- end
4
+ include ::Twat::Exceptions
9
5
 
10
- def config
11
- @config ||= Config.new
6
+ def config_path
7
+ @config_path ||= ENV['TWAT_CONFIG'] || "#{ENV['HOME']}/.twatrc"
12
8
  end
13
- end
14
9
 
15
- class Config
10
+ def exists?
11
+ File.exist?(config_path)
12
+ end
16
13
 
17
- def config_path
18
- @config_path ||= ENV['TWAT_CONFIG'] || "#{ENV['HOME']}/.twatrc"
14
+ def create!
15
+ @config = { accounts: {} }
16
+ save!
19
17
  end
20
18
 
21
19
  def create_unless_exists!
@@ -57,13 +55,15 @@ module Twat
57
55
  end
58
56
 
59
57
  def colors?
60
- colors = config[:colors] || "true"
61
- Options.bool_true?(colors)
58
+ config[:colors].nil? ? false : config[:colors]
62
59
  end
63
60
 
64
61
  def beep?
65
- beep = config[:beep] || "false"
66
- Options.bool_true?(beep)
62
+ config[:beep].nil? ? false : config[:beep]
63
+ end
64
+
65
+ def show_mentions?
66
+ config[:show_mentions].nil? ? false : config[:show_mentions]
67
67
  end
68
68
 
69
69
  def polling_interval
@@ -78,34 +78,22 @@ module Twat
78
78
  # it does this by calling a sequence of migration functions in order
79
79
  # which rebuild the config in stages, saving and leaving it in a
80
80
  # consistent step at each point
81
- def update!
81
+ def update_config
82
+ raise NoConfigFile unless exists?
82
83
  Migrate.new.migrate!(config_path)
83
84
  end
84
85
 
85
- # I don't know how rubyists feel about method returning something vastly
86
- # different to what method= accepts, but I think the api makes sense
87
- def account=(acct)
88
- if accounts.include?(acct)
89
- @account = acct
90
- else
91
- raise NoSuchAccount
92
- end
93
- end
94
-
95
- def account_set?
96
- !!@account
97
- end
98
-
99
86
  def account_name
100
- if account_set?
101
- @account
87
+ if $args[:account]
88
+ return $args[:account].to_sym
102
89
  else
103
- raise NoDefaultAccount unless config.include?(:default)
90
+ raise ::Twat::Exceptions::NoDefaultAccount unless config.include?(:default)
104
91
  return config[:default].to_sym
105
92
  end
106
93
  end
107
94
 
108
95
  def account
96
+ raise NoSuchAccount unless accounts.include?(account_name)
109
97
  accounts[account_name]
110
98
  end
111
99