tinylinks 0.1.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff3190a474ea8e4c3d3591730b77295d59d806034dce59410a5ebc08a9d8c540
4
- data.tar.gz: 2019b549e6959fabc443a06414a3e1567cf5f38954a5a583834dd0bb2d9aef04
3
+ metadata.gz: bd4a470b6c9c25a8e96eb05ae5daaca8f40b3568110c0b70dd3f4e015e70aef3
4
+ data.tar.gz: b67838e3360ac7487dd844b17d67e3c92a1b04b5fff5bb1781a060f74104d91b
5
5
  SHA512:
6
- metadata.gz: b6ca05746fc41a5f2ee89a37ce46e60079676bd9b7cc5bacf7c7bce7fdf6251b791f59056efc9ef3d923d05bd04560a03a66bb99cbf664aef652d31266bd1484
7
- data.tar.gz: c43ba22c4aeab230476184cc4aaf776b12f40b75e3efeaee1072e24039f39f7265be355dd94744edbc583873d4ca161ea7eb83fc52967b6cc67da05876cceab6
6
+ metadata.gz: 32d3af576e893be5c0c865d1ac14aa715451c65114611bf0a0ebf2f3df63c4505613920a8ddc25bfca70f0da83a6bc84ce91dfe8ffdb4060fb262cb353de89e5
7
+ data.tar.gz: 9f391f8ddf3d190b196c9831daefe014f7fed0f5954fcb327ee3471e7d185492d3b0f5975ed0c55814ee2c79f13c2c104a0c4ed3aafb737bcadcbc9c4acb5f16
data/lib/tinylinks/cli.rb CHANGED
@@ -9,6 +9,7 @@ module Tinylinks
9
9
  end
10
10
 
11
11
  class_option :help, aliases: "-h", type: :boolean, desc: "Show help for a command"
12
+ class_option :no_color, type: :boolean, default: false, desc: "Disable color output"
12
13
 
13
14
  no_commands do
14
15
  def invoke_command(command, *args)
@@ -19,9 +20,9 @@ module Tinylinks
19
20
  super
20
21
  rescue Client::ApiError => e
21
22
  if e.body.is_a?(Hash) && e.body["errors"]
22
- say_error formatter.errors(e.body)
23
+ say_error error_formatter.errors(e.body)
23
24
  else
24
- say_error e.message
25
+ say_error error_colorizer.red(e.message)
25
26
  end
26
27
  exit 1
27
28
  end
@@ -45,7 +46,7 @@ module Tinylinks
45
46
  end
46
47
  say "Login successful!"
47
48
  rescue RuntimeError => e
48
- say_error "Login failed: #{e.message}"
49
+ say_error error_colorizer.red("Login failed: #{e.message}")
49
50
  exit 1
50
51
  end
51
52
 
@@ -57,10 +58,16 @@ module Tinylinks
57
58
 
58
59
  desc "list", "List links"
59
60
  method_option :tags, type: :string, desc: "Filter by tags (comma-separated)"
61
+ method_option :filter, type: :string, enum: %w[visited unvisited],
62
+ desc: "Filter by visit status: visited or unvisited"
63
+ method_option :sort, type: :string, enum: %w[newest oldest most_visited least_visited],
64
+ desc: "Sort order: newest (default), oldest, most_visited, least_visited"
60
65
  method_option :page, type: :numeric, desc: "Page number"
61
66
  def list
62
67
  params = {}
63
68
  params[:tags] = options[:tags] if options[:tags]
69
+ params[:filter] = options[:filter] if options[:filter]
70
+ params[:sort] = options[:sort] if options[:sort]
64
71
  params[:page] = options[:page] if options[:page]
65
72
  data = client.get("/links", params)
66
73
  say formatter.link_list(data)
@@ -96,7 +103,7 @@ module Tinylinks
96
103
  body[:tags] = options[:tags].split(",").map(&:strip) if options[:tags]
97
104
 
98
105
  if body.empty?
99
- say_error "No changes specified. Use --title, --description, or --tags."
106
+ say_error error_colorizer.red("No changes specified. Use --title, --description, or --tags.")
100
107
  exit 1
101
108
  end
102
109
 
@@ -142,7 +149,7 @@ module Tinylinks
142
149
  @client ||= begin
143
150
  token = Auth.new.token
144
151
  unless token
145
- say_error "Not logged in. Run `tinylinks login` first."
152
+ say_error error_colorizer.red("Not logged in. Run `tinylinks login` first.")
146
153
  exit 1
147
154
  end
148
155
  Client.new(token: token)
@@ -150,11 +157,23 @@ module Tinylinks
150
157
  end
151
158
 
152
159
  def formatter
153
- @formatter ||= Formatter.new
160
+ @formatter ||= Formatter.new(color: color_enabled?($stdout))
161
+ end
162
+
163
+ def error_formatter
164
+ @error_formatter ||= Formatter.new(color: color_enabled?($stderr))
165
+ end
166
+
167
+ def error_colorizer
168
+ @error_colorizer ||= Colorizer.new(enabled: color_enabled?($stderr))
154
169
  end
155
170
 
156
171
  def say_error(message)
157
172
  $stderr.puts message
158
173
  end
174
+
175
+ def color_enabled?(io)
176
+ !options[:no_color] && io.tty? && ENV["NO_COLOR"].nil?
177
+ end
159
178
  end
160
179
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tinylinks
4
+ class Colorizer
5
+ def initialize(enabled: true)
6
+ @enabled = enabled
7
+ end
8
+
9
+ def bold(text) = wrap(text, 1)
10
+ def dim(text) = wrap(text, 2)
11
+ def red(text) = wrap(text, 31)
12
+ def green(text) = wrap(text, 32)
13
+ def cyan(text) = wrap(text, 36)
14
+
15
+ private
16
+
17
+ def wrap(text, code)
18
+ return text unless @enabled
19
+ "\e[#{code}m#{text}\e[0m"
20
+ end
21
+ end
22
+ end
@@ -2,33 +2,60 @@
2
2
 
3
3
  module Tinylinks
4
4
  class Formatter
5
+ def initialize(color: false)
6
+ @c = Colorizer.new(enabled: color)
7
+ end
8
+
5
9
  def link(data)
6
10
  lines = []
7
- lines << "#{data["title"] || "(untitled)"} [##{data["id"]}]"
8
- lines << " #{data["url"]}"
9
- lines << " #{data["description"]}" if data["description"] && !data["description"].empty?
10
- lines << " tags: #{data["tags"].join(", ")}" if data["tags"] && !data["tags"].empty?
11
+ lines << @c.bold("#{data["title"] || "(untitled)"} [##{data["id"]}]")
12
+ lines << " #{@c.cyan(data["url"])}"
13
+ lines << " #{@c.dim(data["description"])}" if data["description"] && !data["description"].empty?
14
+ meta = meta_line(data)
15
+ lines << " #{meta}" if meta
11
16
  lines.join("\n")
12
17
  end
13
18
 
14
19
  def link_list(data)
20
+ return @c.dim("No results found") if data["links"].empty?
21
+
15
22
  lines = data["links"].map { |l| link(l) }
16
- lines << pagination(data["meta"]) if data["meta"]
23
+ lines << @c.dim(pagination(data["meta"])) if data["meta"]
17
24
  lines.join("\n\n")
18
25
  end
19
26
 
20
27
  def tags(data)
21
- data["tags"].map { |t| "#{t["name"]} (#{t["count"]})" }.join("\n")
28
+ return @c.dim("No results found") if data["tags"].empty?
29
+
30
+ data["tags"].map { |t| "#{@c.green(t["name"])} #{@c.dim("(#{t["count"]})")}" }.join("\n")
22
31
  end
23
32
 
24
33
  def errors(data)
25
34
  data["errors"].flat_map do |field, messages|
26
- messages.map { |msg| "#{field} #{msg}" }
35
+ messages.map { |msg| @c.red("#{field} #{msg}") }
27
36
  end.join("\n")
28
37
  end
29
38
 
30
39
  private
31
40
 
41
+ def meta_line(data)
42
+ parts = []
43
+ parts << "tags: #{@c.green(data["tags"].join(", "))}" if data["tags"] && !data["tags"].empty?
44
+ if data.key?("visit_count") && !data["visit_count"].nil?
45
+ parts << @c.dim(visits_label(data["visit_count"]))
46
+ end
47
+ return if parts.empty?
48
+ parts.join(@c.dim(" · "))
49
+ end
50
+
51
+ def visits_label(count)
52
+ case count
53
+ when 0 then "never visited"
54
+ when 1 then "1 visit"
55
+ else "#{count} visits"
56
+ end
57
+ end
58
+
32
59
  def pagination(meta)
33
60
  "Page #{meta["page"]} of #{meta["total_pages"]} (#{meta["total_items"]} total)"
34
61
  end
data/lib/tinylinks.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tinylinks
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  BASE_URL = "https://links.pati.to"
6
6
  API_BASE = "#{BASE_URL}/api/v1"
7
7
  end
8
8
 
9
+ require_relative "tinylinks/colorizer"
9
10
  require_relative "tinylinks/client"
10
11
  require_relative "tinylinks/auth"
11
12
  require_relative "tinylinks/formatter"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tinylinks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaime Rodas
@@ -34,6 +34,7 @@ files:
34
34
  - lib/tinylinks/auth.rb
35
35
  - lib/tinylinks/cli.rb
36
36
  - lib/tinylinks/client.rb
37
+ - lib/tinylinks/colorizer.rb
37
38
  - lib/tinylinks/formatter.rb
38
39
  homepage: https://github.com/jaimerodas/tinylinks-cli
39
40
  licenses:
@@ -53,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
54
  - !ruby/object:Gem::Version
54
55
  version: '0'
55
56
  requirements: []
56
- rubygems_version: 4.0.6
57
+ rubygems_version: 4.0.10
57
58
  specification_version: 4
58
59
  summary: CLI for TinyLinks
59
60
  test_files: []