anyicon 1.0.3 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f72fd662c558d005d5707b0d42bff57d58bab8642b220a1997486c45f32553c
4
- data.tar.gz: f3a4bf9cc2d295817735260d97b716356b4d46c269cd8eaac67f867a70a39a77
3
+ metadata.gz: cf910787f8f2afc33957a422c85c68bb6453522921dd9d1bbe8af16abea8370a
4
+ data.tar.gz: 4b3a381baec2cfd44707c1ac7bb37d2ccb5b23fa607d05695c4e827582559320
5
5
  SHA512:
6
- metadata.gz: e32588d33dd2178c2ebbf91306c1a72ecce49af1c4b9c7f32410fbabfe70aca1f237bda6e1a7e16f92bde8c2112ffb754fe2a6529402d5d2880aea1912cb357d
7
- data.tar.gz: ce2ae69a8c52fe073b155f12e85f1fcfb73913ceab1ad977e9f74b4c6b1e7ab22994b2dfff56729c97a71ba53060c93432482768abe02e9eede8e52f346ae0e6
6
+ metadata.gz: 60e1cb0856388ebf05ddd3cb4bd037445fc0e8191355079a8ee62b79f09f42e55b3be238484248af4a1578551b3fdc1e84e01a46c37e8481b84d325c9883ef72
7
+ data.tar.gz: '07293138a74f9cea182743a7700cd9cb8f3af4bd3e6dfd8fc2781b522ef1cc42c2f4d8fcb8a2cdd42cd583af9d48f81806271060b8f20b09b1441c97d0bb423e'
data/README.md CHANGED
@@ -47,6 +47,11 @@ You can just use the anyicon helper in your views:
47
47
  ```erb
48
48
  <%= anyicon icon: 'fontawesome_regular:address-book' %>
49
49
  ```
50
+ or
51
+
52
+ ```erb
53
+ <%= anyicon 'fontawesome_regular:address-book' %>
54
+ ```
50
55
 
51
56
  ## Configuration
52
57
 
@@ -61,6 +66,33 @@ Anyicon.configure do |config|
61
66
  end
62
67
  ```
63
68
 
69
+ Or add new collections while keeping the defaults:
70
+
71
+ ```ruby
72
+ Anyicon.configure do |config|
73
+ config.add_collections(
74
+ my_custom_collection: { repo: 'user/repo', path: 'path/to/icons', branch: 'main' }
75
+ )
76
+ end
77
+ ```
78
+
79
+ ### GitHub Token
80
+
81
+ Anyicon fetches icons from GitHub. Without authentication, the GitHub API limits requests to **60 per hour**. If you use `Anyicon::Collection` to download entire collections, or your app fetches many icons on first deploy, you may hit this limit.
82
+
83
+ Setting a GitHub personal access token raises the limit to **5,000 requests per hour**. The token is also used when downloading individual icons.
84
+
85
+ ```ruby
86
+ # config/initializers/anyicon.rb
87
+ Anyicon.configure do |config|
88
+ config.github_token = ENV["GITHUB_TOKEN"]
89
+ end
90
+ ```
91
+
92
+ To create a token, go to [GitHub Settings > Developer settings > Personal access tokens > Fine-grained tokens](https://github.com/settings/tokens?type=beta) and generate a token. No special permissions/scopes are needed — public repository read access is sufficient.
93
+
94
+ > **Note:** This is optional. If you only use a few icons and they are already cached locally in `app/assets/images/icons/`, no API calls are made and no token is needed.
95
+
64
96
  ## Collections Available
65
97
 
66
98
  | Collection | Github List | Example | Quantity | License |
@@ -85,13 +117,28 @@ Please, read the license before using any of these collections. This gem does no
85
117
 
86
118
  Fell free to add your own collection to this list.
87
119
 
120
+ ## Demo
121
+
122
+ To see Anyicon in action with an interactive demo page:
123
+
124
+ ```sh
125
+ git clone https://github.com/arthurmolina/anyicon.git
126
+ cd anyicon
127
+ bundle install
128
+ RAILS_ENV=development bundle exec rackup -p 3000 test/dummy/config.ru
129
+ ```
130
+
131
+ Then open [http://localhost:3000/demo](http://localhost:3000/demo).
132
+
133
+ The demo showcases basic usage, sizing, colors, HTML/data/aria attributes, inline text components, and CSS animations.
134
+
88
135
  ## Development
89
136
 
90
137
  To get started with development:
91
138
 
92
- ```
139
+ ```sh
93
140
  git clone https://github.com/arthurmolina/anyicon.git
94
- cd heroicon
141
+ cd anyicon
95
142
  bundle install
96
143
  bundle exec rake test
97
144
  ```
@@ -8,8 +8,8 @@ module Anyicon
8
8
  # @param icon [String] the name of the icon in the format 'collection:icon_name'
9
9
  # @param props [Hash] additional properties to apply to the SVG element
10
10
  # @return [String] the rendered SVG icon
11
- def anyicon(icon:, **props)
12
- Anyicon::Icon.render(icon:, **props)
11
+ def anyicon(icon = nil, **props)
12
+ Anyicon::Icon.render(icon, **props)
13
13
  end
14
14
  end
15
15
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'net/http'
4
- require 'json'
5
- require 'fileutils'
3
+ require "net/http"
4
+ require "json"
5
+ require "fileutils"
6
6
 
7
7
  module Anyicon
8
8
  # The Collection class is responsible for managing icon collections
@@ -31,7 +31,8 @@ module Anyicon
31
31
  # @return [Array<Hash>] a list of icons with their metadata
32
32
  def list
33
33
  response = fetch(collection_url)
34
- JSON.parse(response&.body || '{}')
34
+ result = JSON.parse(response&.body || "[]")
35
+ result.is_a?(Array) ? result : []
35
36
  end
36
37
 
37
38
  # Downloads all icons in the collection and saves them to the local file system.
@@ -39,7 +40,7 @@ module Anyicon
39
40
  # @return [void]
40
41
  def download_all
41
42
  if list.empty?
42
- puts 'No icons available.'
43
+ ::Rails.logger.info "AnyIcon: No icons available for #{@collection}."
43
44
  return
44
45
  end
45
46
 
@@ -48,7 +49,7 @@ module Anyicon
48
49
  count += 1
49
50
  download(icon)
50
51
  end
51
- puts "#{@collection}: #{count} downloads."
52
+ ::Rails.logger.info "AnyIcon: #{@collection}: #{count} downloads."
52
53
  end
53
54
 
54
55
  # Retrieves the configured collections from Anyicon.
@@ -65,12 +66,12 @@ module Anyicon
65
66
  # @param icon [Hash] the metadata of the icon to download
66
67
  # @return [void]
67
68
  def download(icon)
68
- return if icon['download_url'].nil?
69
- return if File.exist?(icon_path(icon['name']))
69
+ return if icon["download_url"].nil?
70
+ return if File.exist?(icon_path(icon["name"]))
70
71
 
71
- FileUtils.mkdir_p(icon_path(icon['name']).dirname)
72
- response = fetch(icon['download_url'])
73
- File.write(icon_path(icon['name']), response.body)
72
+ FileUtils.mkdir_p(icon_path(icon["name"]).dirname)
73
+ response = fetch(icon["download_url"])
74
+ File.write(icon_path(icon["name"]), response.body)
74
75
  rescue ActionView::Template::Error, Net::HTTPError, Net::HTTPClientException => e
75
76
  ::Rails.logger.error "AnyIcon: Failed to download icon: #{e.message}"
76
77
  end
@@ -80,21 +81,25 @@ module Anyicon
80
81
  # @param icon_name [String] the name of the icon
81
82
  # @return [Pathname] the path to the icon file
82
83
  def icon_path(icon_name)
83
- ::Rails.root.join('app', 'assets', 'images', 'icons', @collection.to_s, icon_name)
84
+ sanitized_collection = File.basename(@collection.to_s.gsub(/[^a-zA-Z0-9_\-]/, ""))
85
+ sanitized_name = File.basename(icon_name.to_s)
86
+ ::Rails.root.join("app", "assets", "images", "icons", sanitized_collection, sanitized_name)
84
87
  end
85
88
 
86
89
  # Constructs the URL to fetch the icon collection directory contents from the repository.
87
90
  #
88
91
  # @return [String, nil] the URL to fetch the collection contents, or nil if the collection is not configured
89
92
  def collection_url
90
- return nil unless collections.keys.include?(@collection)
93
+ return nil unless collections.key?(@collection)
91
94
 
92
95
  [
93
- 'https://api.github.com/repos/',
96
+ "https://api.github.com/repos/",
94
97
  collections[@collection][:repo],
95
- '/contents/',
96
- collections[@collection][:path]
97
- ].join('')
98
+ "/contents/",
99
+ collections[@collection][:path],
100
+ "?ref=",
101
+ collections[@collection][:branch]
102
+ ].join("")
98
103
  end
99
104
  end
100
105
  end
@@ -12,6 +12,8 @@ module Anyicon
12
12
  # response = common.fetch('https://example.com')
13
13
  # puts response.body if response.is_a?(Net::HTTPSuccess)
14
14
  class Common
15
+ ALLOWED_HOSTS = %w[github.com raw.githubusercontent.com objects.githubusercontent.com api.github.com].freeze
16
+
15
17
  # Fetches the content from the given URL, following redirects if necessary.
16
18
  #
17
19
  # @param url [String] the URL to fetch
@@ -19,15 +21,25 @@ module Anyicon
19
21
  # @return [Net::HTTPResponse] the HTTP response
20
22
  # @raise [Net::HTTPError] if the number of redirects exceeds the limit or another HTTP error occurs
21
23
  def fetch(url, limit = 10)
22
- raise Net::HTTPError, 'Too many HTTP redirects' if limit.zero?
24
+ raise Net::HTTPError.new("Too many HTTP redirects", nil) if limit.zero?
23
25
  return nil if url.nil?
24
26
 
25
- uri = URI.parse(URI::DEFAULT_PARSER.escape(url))
26
- response = Net::HTTP.get_response(uri)
27
+ uri = URI.parse(URI::RFC2396_PARSER.escape(url))
28
+ unless uri.is_a?(URI::HTTPS) && ALLOWED_HOSTS.include?(uri.host)
29
+ raise Net::HTTPError.new("Blocked request to disallowed host: #{uri.host}", nil)
30
+ end
31
+
32
+ request = Net::HTTP::Get.new(uri)
33
+ token = Anyicon.configuration.github_token
34
+ request["Authorization"] = "token #{token}" if token
35
+
36
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
37
+ http.request(request)
38
+ end
27
39
 
28
40
  case response
29
41
  when Net::HTTPSuccess then response
30
- when Net::HTTPRedirection then fetch(response['location'], limit - 1)
42
+ when Net::HTTPRedirection then fetch(response["location"], limit - 1)
31
43
  else
32
44
  response.error!
33
45
  end
@@ -22,29 +22,33 @@ module Anyicon
22
22
  # A hash containing the default icon collections. Each collection specifies the
23
23
  # repository, path, and branch where the icons can be found.
24
24
  DEFAULT_COLLECTIONS = {
25
- fontawesome_regular: { repo: 'FortAwesome/Font-Awesome', path: 'svgs/regular', branch: '6.x' },
26
- fontawesome_solid: { repo: 'FortAwesome/Font-Awesome', path: 'svgs/solid', branch: '6.x' },
27
- fontawesome_brands: { repo: 'FortAwesome/Font-Awesome', path: 'svgs/brands', branch: '6.x' },
28
- heroicons_outline: { repo: 'tailwindlabs/heroicons', path: 'optimized/24/outline', branch: 'master' },
29
- heroicons_solid: { repo: 'tailwindlabs/heroicons', path: 'optimized/24/solid', branch: 'master' },
30
- tabler_icons_filled: { repo: 'tabler/tabler-icons', path: 'icons/filled', branch: 'main' },
31
- tabler_icons_outline: { repo: 'tabler/tabler-icons', path: 'icons/outline', branch: 'main' },
32
- mage_icons_fill: { repo: 'Mage-Icons/mage-icons', path: 'svg/bulk', branch: 'main' },
33
- mage_icons_stroke: { repo: 'Mage-Icons/mage-icons', path: 'svg/stroke', branch: 'main' },
34
- mage_icons_social_bw: { repo: 'Mage-Icons/mage-icons', path: 'svg/social-bw', branch: 'main' },
35
- mage_icons_social_color: { repo: 'Mage-Icons/mage-icons', path: 'svg/social-color', branch: 'main' },
36
- line_awesome: { repo: 'icons8/line-awesome', path: 'svg', branch: 'master' },
37
- carbon: { repo: 'carbon-design-system/carbon', path: 'packages/icons/src/svg/32', branch: 'main' },
38
- ionicons: { repo: 'ionic-team/ionicons', path: 'src/svg', branch: 'main' },
39
- feather_icons: { repo: 'feathericons/feather', path: 'icons', branch: 'main' }
25
+ fontawesome_regular: { repo: "FortAwesome/Font-Awesome", path: "svgs/regular", branch: "6.x" },
26
+ fontawesome_solid: { repo: "FortAwesome/Font-Awesome", path: "svgs/solid", branch: "6.x" },
27
+ fontawesome_brands: { repo: "FortAwesome/Font-Awesome", path: "svgs/brands", branch: "6.x" },
28
+ heroicons_outline: { repo: "tailwindlabs/heroicons", path: "optimized/24/outline", branch: "master" },
29
+ heroicons_solid: { repo: "tailwindlabs/heroicons", path: "optimized/24/solid", branch: "master" },
30
+ tabler_icons_filled: { repo: "tabler/tabler-icons", path: "icons/filled", branch: "main" },
31
+ tabler_icons_outline: { repo: "tabler/tabler-icons", path: "icons/outline", branch: "main" },
32
+ mage_icons_fill: { repo: "Mage-Icons/mage-icons", path: "svg/bulk", branch: "main" },
33
+ mage_icons_stroke: { repo: "Mage-Icons/mage-icons", path: "svg/stroke", branch: "main" },
34
+ mage_icons_social_bw: { repo: "Mage-Icons/mage-icons", path: "svg/social-bw", branch: "main" },
35
+ mage_icons_social_color: { repo: "Mage-Icons/mage-icons", path: "svg/social-color", branch: "main" },
36
+ line_awesome: { repo: "icons8/line-awesome", path: "svg", branch: "master" },
37
+ carbon: { repo: "carbon-design-system/carbon", path: "packages/icons/src/svg/32", branch: "main" },
38
+ ionicons: { repo: "ionic-team/ionicons", path: "src/svg", branch: "main" },
39
+ feather_icons: { repo: "feathericons/feather", path: "icons", branch: "main" }
40
40
  }.freeze
41
41
 
42
42
  # @return [Hash] the configured icon collections
43
43
  attr_accessor :collections
44
44
 
45
+ # @return [String, nil] optional GitHub personal access token for API requests
46
+ attr_accessor :github_token
47
+
45
48
  # Initializes a new Configuration instance with default settings.
46
49
  def initialize
47
50
  @collections = DEFAULT_COLLECTIONS.dup
51
+ @github_token = nil
48
52
  end
49
53
 
50
54
  def add_collections(new_collections)
data/lib/anyicon/icon.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'net/http'
4
- require 'nokogiri'
5
- require 'fileutils'
3
+ require "net/http"
4
+ require "nokogiri"
5
+ require "fileutils"
6
6
 
7
7
  module Anyicon
8
8
  # The Icon class is responsible for managing the rendering of icons from various
@@ -21,22 +21,29 @@ module Anyicon
21
21
  #
22
22
  # @param icon [String] a comma-separated string of icon names, each in the format 'collection:name'
23
23
  # @param props [Hash] additional properties to apply to the SVG element
24
- def initialize(icon:, **props)
24
+ ALLOWED_ATTRIBUTES = %w[
25
+ class id style width height viewBox fill stroke
26
+ stroke-width opacity transform title aria-label aria-hidden role
27
+ ].freeze
28
+
29
+ DATA_ATTRIBUTE_PATTERN = /\Adata-[\w-]+\z/
30
+
31
+ def initialize(icon = nil, **props)
25
32
  super()
26
- @icons = icon.to_s.split(',').map { |i| i.split(':') }
27
- @props = props
33
+ @icons = (icon || props[:icon]).to_s.split(",").map { |i| i.split(":") }
34
+ @icons.reject! { |i| i.length < 2 }
35
+ @props = props.select { |key, _| allowed_attribute?(key) }
28
36
  end
29
37
 
30
38
  # Renders the SVG content for the specified icons.
31
39
  #
32
40
  # @return [String] the HTML-safe SVG content
33
41
  def render
34
- result = ''.html_safe
35
- @icons.each do |icon|
42
+ parts = @icons.map do |icon|
36
43
  ensure_icon_exists(icon)
37
- result.concat(svg_content(icon).html_safe)
44
+ svg_content(icon)
38
45
  end
39
- result
46
+ ActiveSupport::SafeBuffer.new(parts.join)
40
47
  end
41
48
 
42
49
  private
@@ -48,6 +55,23 @@ module Anyicon
48
55
  @collections ||= Anyicon.configuration.collections
49
56
  end
50
57
 
58
+ # Checks if an attribute key is allowed on the SVG element.
59
+ #
60
+ # @param key [Symbol, String] the attribute key
61
+ # @return [Boolean]
62
+ def allowed_attribute?(key)
63
+ name = key.to_s
64
+ ALLOWED_ATTRIBUTES.include?(name) || name.match?(DATA_ATTRIBUTE_PATTERN)
65
+ end
66
+
67
+ # Sanitizes an icon name component to prevent path traversal.
68
+ #
69
+ # @param name [String] the raw icon name component
70
+ # @return [String] the sanitized name
71
+ def sanitize_name(name)
72
+ File.basename(name.to_s.gsub(/[^a-zA-Z0-9_\-]/, ""))
73
+ end
74
+
51
75
  # Ensures the specified icon exists by downloading it if necessary.
52
76
  #
53
77
  # @param icon [Array] the collection and name of the icon
@@ -76,7 +100,7 @@ module Anyicon
76
100
  # @param icon [Array] the collection and name of the icon
77
101
  # @return [Pathname] the path to the icon file
78
102
  def icon_path(icon)
79
- ::Rails.root.join('app', 'assets', 'images', 'icons', icon[0], "#{icon[1]}.svg")
103
+ ::Rails.root.join("app", "assets", "images", "icons", sanitize_name(icon[0]), "#{sanitize_name(icon[1])}.svg")
80
104
  end
81
105
 
82
106
  # Constructs the URL to download the specified icon.
@@ -84,10 +108,22 @@ module Anyicon
84
108
  # @param icon [Array] the collection and name of the icon
85
109
  # @return [String, nil] the URL to download the icon, or nil if the collection is not configured
86
110
  def icon_url(icon)
87
- return nil unless collections.keys.include?(icon[0].to_sym)
111
+ collection_key = sanitize_name(icon[0]).to_sym
112
+ return nil unless collections.key?(collection_key)
113
+
114
+ [ "https://github.com/", collections[collection_key][:repo], "/raw/", collections[collection_key][:branch], "/",
115
+ collections[collection_key][:path], "/", sanitize_name(icon[1]), ".svg" ].join("")
116
+ end
88
117
 
89
- ['https://github.com/', collections[icon[0].to_sym][:repo], '/raw/', collections[icon[0].to_sym][:branch], '/',
90
- collections[icon[0].to_sym][:path], '/', icon[1], '.svg'].join('')
118
+ # Returns the cached raw SVG content for the specified icon.
119
+ #
120
+ # @param icon [Array] the collection and name of the icon
121
+ # @return [String, nil] the raw SVG file content, or nil if file doesn't exist
122
+ def cached_svg(icon)
123
+ path = icon_path(icon)
124
+ return nil unless File.file?(path)
125
+
126
+ self.class.svg_cache[path.to_s] ||= File.read(path)
91
127
  end
92
128
 
93
129
  # Reads and customizes the SVG content for the specified icon.
@@ -95,11 +131,11 @@ module Anyicon
95
131
  # @param icon [Array] the collection and name of the icon
96
132
  # @return [String] the customized SVG content
97
133
  def svg_content(icon)
98
- return '' unless File.file?(icon_path(icon))
134
+ raw = cached_svg(icon)
135
+ return "" unless raw
99
136
 
100
- svg_content = File.read(icon_path(icon))
101
- doc = Nokogiri::HTML::DocumentFragment.parse(svg_content)
102
- svg = doc.at_css 'svg'
137
+ doc = Nokogiri::HTML::DocumentFragment.parse(raw)
138
+ svg = doc.at_css "svg"
103
139
 
104
140
  @props.each do |key, value|
105
141
  value = "#{value} #{icon[-2..].join(' ')}" if key == :class && icon.count > 2
@@ -115,8 +151,21 @@ module Anyicon
115
151
  #
116
152
  # @param kwargs [Hash] the parameters for initializing an Icon instance
117
153
  # @return [String] the HTML-safe SVG content
118
- def render(**kwargs)
119
- new(**kwargs).render
154
+ def render(*args, **kwargs)
155
+ new(*args, **kwargs).render
156
+ end
157
+
158
+ # In-memory cache for raw SVG file contents, keyed by file path.
159
+ # Avoids repeated File.read + disk I/O for the same icon.
160
+ #
161
+ # @return [Hash] the SVG cache
162
+ def svg_cache
163
+ @svg_cache ||= {}
164
+ end
165
+
166
+ # Clears the in-memory SVG cache.
167
+ def clear_cache!
168
+ @svg_cache = {}
120
169
  end
121
170
  end
122
171
  end
@@ -1,3 +1,3 @@
1
1
  module Anyicon
2
- VERSION = "1.0.3"
2
+ VERSION = "1.1.1"
3
3
  end
data/lib/anyicon.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails'
4
- require 'anyicon/engine'
5
- require 'anyicon/common'
6
- require 'anyicon/collections'
7
- require 'anyicon/icon'
8
- require 'anyicon/configuration'
3
+ require "rails"
4
+ require "anyicon/engine"
5
+ require "anyicon/common"
6
+ require "anyicon/collections"
7
+ require "anyicon/icon"
8
+ require "anyicon/configuration"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails/generators'
3
+ require "rails/generators"
4
4
 
5
5
  module Anyicon
6
6
  module Generators
@@ -17,14 +17,14 @@ module Anyicon
17
17
  # This will copy the `anyicon.rb` template to `config/initializers/anyicon.rb` in your
18
18
  # Rails application.
19
19
  class InstallGenerator < ::Rails::Generators::Base
20
- source_root File.join(__dir__, 'templates')
21
- desc 'This generator installs AnyIcon'
20
+ source_root File.join(__dir__, "templates")
21
+ desc "This generator installs AnyIcon"
22
22
 
23
23
  # Copies the anyicon configuration template to the initializers directory.
24
24
  #
25
25
  # @return [void]
26
26
  def copy_config
27
- template 'anyicon.rb', 'config/initializers/anyicon.rb'
27
+ template "anyicon.rb", "config/initializers/anyicon.rb"
28
28
  end
29
29
  end
30
30
  end
@@ -15,4 +15,11 @@ Anyicon.configure do |config|
15
15
  # }
16
16
  # )
17
17
  #
18
+
19
+ ##
20
+ # Optional: Set a GitHub personal access token to avoid API rate limits
21
+ # (60 requests/hour unauthenticated vs 5,000/hour authenticated).
22
+ #
23
+ # config.github_token = ENV["GITHUB_TOKEN"]
24
+ #
18
25
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :anyicon do
4
- desc 'Download a specific icon collection'
5
- task :download_collection, [:collection] => :environment do |_t, args|
4
+ desc "Download a specific icon collection"
5
+ task :download_collection, [ :collection ] => :environment do |_t, args|
6
6
  collection = args[:collection]
7
7
  if Anyicon.configuration.collections.keys.include?(collection.to_sym)
8
8
  Anyicon::Collection.new(collection.to_sym).download_all
@@ -11,9 +11,9 @@ namespace :anyicon do
11
11
  end
12
12
  end
13
13
 
14
- desc 'Download all icon collections'
14
+ desc "Download all icon collections"
15
15
  task download_all_collections: :environment do
16
- puts 'Downloading all icon collections'
16
+ puts "Downloading all icon collections"
17
17
  Anyicon.configuration.collections.each_key do |collection|
18
18
  puts "Downloading #{collection}..."
19
19
  Anyicon::Collection.new(collection).download_all
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anyicon
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arthur Molina
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-07-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -24,6 +23,20 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: '5.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: nokogiri
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
27
40
  - !ruby/object:Gem::Dependency
28
41
  name: appraisal
29
42
  requirement: !ruby/object:Gem::Requirement
@@ -139,7 +152,6 @@ metadata:
139
152
  source_code_uri: https://github.com/arthurmolina/anyicon
140
153
  bug_tracker_uri: https://github.com/arthurmolina/anyicon/issues
141
154
  wiki_uri: https://github.com/arthurmolina/anyicon/wiki
142
- post_install_message:
143
155
  rdoc_options: []
144
156
  require_paths:
145
157
  - lib
@@ -154,8 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
166
  - !ruby/object:Gem::Version
155
167
  version: '0'
156
168
  requirements: []
157
- rubygems_version: 3.5.16
158
- signing_key:
169
+ rubygems_version: 3.6.9
159
170
  specification_version: 4
160
171
  summary: Rails View Helpers for any icon collections.
161
172
  test_files: []