qr_forge 1.0.0 → 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: 379423936d868bc8e4589d3483cc412c1bd6ec85bd6b9ae82e9ad58dfeb03903
4
- data.tar.gz: 815cf224b5876c0222e8449b5edcbcc35d4f00c53d800f0a4cddb54d31f42735
3
+ metadata.gz: 68e6f3102dc3d6954c036f6bfb17a2820743956eea34b7ef11565f173cab0a9a
4
+ data.tar.gz: e3d5a5c12559c0cf707537ce5163d10717e0f1c18a39130cfb5ba940bc71647d
5
5
  SHA512:
6
- metadata.gz: 75c947677801f0d3d4469d3544206f9f3d0755ef90444b2eec312cf6373a0a2e10661d86a7f97d574ff69d05accb797299699d9bfd6f517b74130ecfe5393765
7
- data.tar.gz: b31403d7730bb7f2bca48f237b8e99fd1a96414c470e24485164dd6046990e337a385bae68eb8832cff3cb2504b3fccdf0ffb5553b91a5d8bc70c7037e0bc10a
6
+ metadata.gz: 33ba1ce62ea6a782dcc019c72f4c94f487c0ea49847485ae888fc9729b27a710741a5a6d5a771113f1617bbec52ba8e5a9d007b9dfc83ac574b08a7c6031c42a
7
+ data.tar.gz: 1f245ef3f6a10dadc97c8eb60d8d74e27aeff4f0258c0cf84989e39c85179c4fe027a1c204f0ef2df838c100b9039feb34d3712a373d986816a579735a09f371
data/.rubocop.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 3.1
3
+ NewCops: enable
3
4
 
4
5
  Style/StringLiterals:
5
6
  EnforcedStyle: double_quotes
@@ -17,4 +18,7 @@ Metrics/ParameterLists:
17
18
  Max: 10
18
19
 
19
20
  Metrics/BlockLength:
20
- Max: 150
21
+ Max: 150
22
+
23
+ Metrics/ClassLength:
24
+ Max: 500
data/README.md CHANGED
@@ -1,39 +1,177 @@
1
- # QrForge
1
+ ![output](https://github.com/user-attachments/assets/6d360bbb-511d-43f4-a356-8adf634efac0)
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ An example of the output of QR Forge
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/qr_forge`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ # QR Forge
6
6
 
7
- ## Installation
7
+ This library is a QR Code renderer that lets you customize almost every aspect of a QR Code. From module design to a logo, this library is meant to be design-extensible, which means you can render your own components such as modules, the outer eyes and inner eyes etc. in your own custom SVG shapes.
8
8
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
9
+ # Installation
10
10
 
11
- Install the gem and add to the application's Gemfile by executing:
11
+ ```shell
12
+ gem install qr_forge
13
+ ```
14
+
15
+ or if using bundler
16
+
17
+ ```shell
18
+ bundle add qr_forge
19
+ ```
20
+
21
+ # Usage
22
+
23
+ To create a QR Code you can simply do the following:
24
+
25
+ ### Payloads
26
+
27
+ Did you know that QR Codes can store different pieces of data such as wifi access, passkeys, geolocation and quite a few more! Below are a few different types of data payloads that are implemented with in the gem. More will be added as needed.
28
+
29
+ #### Plain text
30
+
31
+ ```ruby
32
+ QrForge::Forge.build(data: "https://yourlinkhere.com", type: :plain)
33
+ ```
34
+
35
+ #### URL
36
+
37
+ ```ruby
38
+ QrForge::Forge.build(data: "https://yourlinkhere.com", type: :url)
39
+ ```
40
+
41
+ #### Wifi
42
+
43
+ ```ruby
44
+ QrForge::Payload.build(data: { ssid: "MyNetwork", password: "MyPassword", encryption: "WPA" }, type: :wifi)
45
+ ```
46
+ Fields:
47
+ - ssid,
48
+ - password
49
+ - encryption (WEP WPA WPA2 WPA3)
50
+ - hidden (true/false)
51
+
52
+ >[!NOTE]
53
+ >You can also pass "nopass" to encryption which means a password does not need to be provided either (public wifi etc.)
54
+
55
+ #### Geo/Coordinates
56
+
57
+ ```ruby
58
+ QrForge::Payload.build(data: { latitude: 40.712776, longitude: -74.005974 }, type: :geo)
59
+ ```
60
+ Fields:
61
+ - latitude
62
+ - longitude
63
+
64
+ #### Phone number
65
+
66
+ ```ruby
67
+ QrForge::Payload.build(data: "+1234567890", type: :phone)
68
+ QrForge::Payload.build(data: "1234567890", type: :phone)
69
+ QrForge::Payload.build(data: "123-456-7890", type: :phone)
70
+ QrForge::Payload.build(data: "(123) 456-7890", type: :phone)
71
+ QrForge::Payload.build(data: "123.456.7890", type: :phone)
72
+ ```
73
+
74
+ More are planned to be added.
75
+
76
+ ### Design
12
77
 
13
- ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
78
+ Design controls the look and feel of the QR Code from the [QR Version](https://www.qrcode.com/en/about/version.html) to the colors of the individual modules.
79
+
80
+ ##### QR
81
+
82
+ ```ruby
83
+ QrForge::Payload.build(..., design: { qr { version: 10 } }, ...)
15
84
  ```
85
+ Fields:
86
+ - Version
87
+
88
+ ##### Image
16
89
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
90
+ ```ruby
91
+ QrForge::Payload.build(..., design: { image: "..." }, ...)
92
+ ```
93
+ The image should be a **Base64 encoded** image like the following:
18
94
 
19
- ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
95
+ ```ruby
96
+ Base64.strict_encode64(image_png_binary)
21
97
  ```
98
+ More image formats will be added as needed or required.
99
+
100
+ ##### Colors
22
101
 
23
- ## Usage
102
+ ```ruby
103
+ QrForge::Payload.build(..., design: {colors: { outer_eye: "#30363D", inner_eye: "#30363D", module: "#484F58" }, ...)
104
+ ```
105
+ Fields:
106
+ - outer_eye
107
+ - inner_eye
108
+ - module
109
+
110
+ Any hex code or plain color such as "red", "cyan", "peru", etc. will work as the color value.
24
111
 
25
- TODO: Write usage instructions here
112
+ See the Components section for more details on which field references what component of the QR Code.
26
113
 
27
- ## Development
114
+ ### Output
28
115
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
116
+ ```ruby
117
+ QrForge::Payload.build(..., output: { size: 250 }, ...)
118
+ ```
119
+ Fields:
120
+ - size
121
+
122
+ QR Codes are equal in height and width, the size will control the width and height of the returned SVG.
30
123
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
124
+ There is only an ouput of SVG format, see this PR for reasoning: https://github.com/keegankb93/qr_forge/pull/1
32
125
 
33
- ## Contributing
126
+ If different formats are a requirement and that requirement means the image conversion should take place in the gem, send me a message with your usecase. SVG as the format should be good for almost all usecases.
34
127
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/qr_forge.
128
+ ### Components
36
129
 
37
- ## License
130
+ ```ruby
131
+ QrForge::Payload.build(..., components: {
132
+ outer_eye: QrForge::Components::EyeOuter::Square,
133
+ inner_eye: QrForge::Components::EyeInner::Square,
134
+ module: QrForge::Components::Module::Squre
135
+ },
136
+ ...)
137
+ ```
138
+ Fields:
139
+ - outer_eye
140
+ <img width="77" alt="Screenshot 2025-06-17 at 1 23 39 AM" src="https://github.com/user-attachments/assets/ccef3f08-cc4b-43c7-95b4-8d6c707f5f5a" />
141
+
142
+ - inner_eye
143
+ <img width="77" alt="Screenshot 2025-06-17 at 1 24 22 AM" src="https://github.com/user-attachments/assets/c21bb175-00c2-4179-a20a-4e505ad37df1" />
144
+
145
+ - module
146
+ <img width="216" alt="Screenshot 2025-06-17 at 1 25 24 AM" src="https://github.com/user-attachments/assets/f670d5fd-e2dc-42cc-9bff-d77a51d65fa1" />
147
+
148
+ You can create your own designs and pass them through as long as they inherit from the ForgeComponent. If you create your own designs, when you pass them through the config, it will merge them with the default components, so if you only want to change one or two of the components, but not all three, you can!
149
+
150
+ >[!NOTE]
151
+ >More designs are to come, so not every facet of qr code manipulation may be available at this time such as module look aheads/behinds. This is >coming soon.
152
+
153
+ ### Example
154
+
155
+ This is the code that was used to create the QR Code at the top of the page.
156
+
157
+ ```ruby
158
+ QrForge::Forge.build(data: "https://www.github.com/keegankb93/qr_forge",
159
+ type: :url,
160
+ config: {
161
+ qr: { version: 5 },
162
+ design: {
163
+ image:,
164
+ colors: {
165
+ outer_eye: "#30363D",
166
+ inner_eye: "#30363D",
167
+ module: "#484F58"
168
+ }
169
+ },
170
+ output: { size: 250 }
171
+ })
172
+ ```
38
173
 
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
174
+ ### Roadmap
175
+ - Color gradients for outer and inner eyes
176
+ - Image background and shape improvements
177
+ - More default component selections
data/Rakefile CHANGED
@@ -7,6 +7,8 @@ RSpec::Core::RakeTask.new(:spec)
7
7
 
8
8
  require "rubocop/rake_task"
9
9
 
10
- RuboCop::RakeTask.new
10
+ RuboCop::RakeTask.new do |task|
11
+ task.fail_on_error = false
12
+ end
11
13
 
12
14
  task default: %i[spec rubocop]
@@ -23,7 +23,7 @@ module QrForge
23
23
  cx: cx,
24
24
  cy: cy,
25
25
  r: r,
26
- 'stroke-width': stroke_width,
26
+ "stroke-width": stroke_width,
27
27
  stroke: color,
28
28
  fill: "transparent",
29
29
  test_id: @test_id
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "vips"
4
-
5
3
  module QrForge
6
4
  #
7
5
  # Handles exporting the generated QR code in various formats.
@@ -10,12 +8,15 @@ module QrForge
10
8
  @format = config.dig(:output, :format) || :svg
11
9
  end
12
10
 
11
+ #
12
+ # Exports the generated QR code in the specified format.
13
+ # @param svg [String] The generated SVG content of the QR code
14
+ # @return [String] The exported QR code in the specified format
15
+ # @raise [RuntimeError] if the format is unsupported
13
16
  def export(svg)
14
17
  case @format
15
18
  when :svg
16
- svg
17
- when :png
18
- as_png(svg)
19
+ process_svg(svg)
19
20
  else
20
21
  raise "Unsupported export format: #{@format}"
21
22
  end
@@ -24,15 +25,23 @@ module QrForge
24
25
  private
25
26
 
26
27
  #
27
- # Exports the SVG to PNG format using Vips.
28
- # @param svg [String] The SVG content to convert
29
- # @return [StringIO] A StringIO object containing the PNG data
30
- def as_png(svg)
31
- image = Vips::Image.svgload_buffer(svg)
32
- # TODO: Compression doesn't really seem to give much noticeable difference in quality or file size.
33
- buffer = image.write_to_buffer(".png")
28
+ # Performs any last-minute processing on the svg before exporting if applicable
29
+ # @param [String] svg the preprocessed svg
30
+ # @return [String] the final svg
31
+ def process_svg(svg)
32
+ return svg if ENV["SVG_OUTPUT_MODE"] == "test"
34
33
 
35
- StringIO.new(buffer)
34
+ clean(svg)
35
+ end
36
+
37
+ #
38
+ # Cleans the SVG by removing test_id attributes.
39
+ # @param svg [String] The generated SVG
40
+ # @return [String] The cleaned SVG content
41
+ def clean(svg)
42
+ doc = Nokogiri::XML(svg)
43
+ doc.xpath("//@test_id").remove
44
+ doc.to_xml
36
45
  end
37
46
  end
38
47
  end
@@ -4,21 +4,25 @@ module QrForge
4
4
  #
5
5
  # Entry point for building QRCodes
6
6
  class Forge
7
- def initialize(text:, config:)
7
+ def initialize(data:, type:, config:)
8
8
  version = config.dig(:qr, :version)
9
9
 
10
- @data = QrForge::QrData.new(text:, version:)
10
+ @data = QrForge::QrData.new(text: QrForge::Payload.build(data:, type:).to_s, version:)
11
11
  @renderer = QrForge::Renderer.new(qr_data: @data, config:)
12
12
  @exporter = QrForge::Exporter.new(config:)
13
13
  end
14
14
 
15
15
  #
16
16
  # Builds a QR code with the given parameters.
17
- # @param text [String] The text/data to encode in the QR code
18
- # @param size [Integer] The size of the QR code in modules [1-40]
19
- # @return [String, StringIO] The SVG or PNG representation of the QR code
20
- def self.build(text:, config: {})
21
- new(text:, config:).build
17
+ # @param data [String, Hash] The data to encode in the QR code. This can be a string or a hash for specific payloads.
18
+ # @param type [Symbol] The type of QR code to build (e.g., :plain, :url)
19
+ # @param config [Hash] Configuration options for the QR code, including design and export settings.
20
+ # - `:qr` - QR code specific settings (e.g., version).
21
+ # - `:design` - Design specific settings (e.g., colors, shapes).
22
+ # - `:output` - Export specific settings (e.g., format).
23
+ # @return [String] The SVG or PNG representation of the QR code
24
+ def self.build(data:, type: :url, config: {})
25
+ new(data:, type:, config:).build
22
26
  end
23
27
 
24
28
  def build
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrForge
4
+ #
5
+ # Payload is a factory class that builds different types of payloads based on the provided type and data.
6
+ # It will validate the payload data (based on the type) and return a string representation of the payload.
7
+ class Payload
8
+ # TODO: Add passkey and sms support and vcard
9
+ PAYLOAD_TYPES = {
10
+ wifi: ::QrForge::Payloads::Wifi,
11
+ plain: ::QrForge::Payloads::PlainText,
12
+ url: ::QrForge::Payloads::Url,
13
+ geo: ::QrForge::Payloads::Geo,
14
+ phone: ::QrForge::Payloads::Phone
15
+ }.freeze
16
+
17
+ #
18
+ # Builds a payload based on the type and data provided.
19
+ # @param type [Symbol] The type of payload to build (e.g., :url, :wifi).
20
+ # @param data [String, Hash] The data to encode in the payload.
21
+ # @return [String] The string representation of the payload.
22
+ def self.build(type:, data:)
23
+ klass = PAYLOAD_TYPES[type.to_sym]
24
+
25
+ raise ArgumentError "Invalid payload type: #{type}" unless klass
26
+
27
+ payload = case data
28
+ when Hash
29
+ klass.new(**data)
30
+ when String
31
+ klass.new(data)
32
+ else
33
+ raise ArgumentError, "Invalid data type: #{data.class}. Expected Hash or String."
34
+ end
35
+
36
+ payload.validate!
37
+ payload
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrForge
4
+ module Payloads
5
+ #
6
+ # Represents a geo lat/long payload
7
+ # @example return "geo:40.712776,-74.005974"
8
+ class Geo
9
+ def initialize(latitude:, longitude:)
10
+ @latitude = latitude
11
+ @longitude = longitude
12
+ end
13
+
14
+ def to_s
15
+ "geo:#{@latitude},#{@longitude}"
16
+ end
17
+
18
+ #
19
+ # Validates that the passed latitude and longitude are within valid ranges.
20
+ def validate!
21
+ return if (-90..90).cover?(@latitude.to_f) && (-180..180).cover?(@longitude.to_f)
22
+
23
+ raise PayloadValidationError, "Latitude or longitude out of range"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrForge
4
+ module Payloads
5
+ #
6
+ # Represents a telephone payload
7
+ # @example return "https://example.com" or "http://example.com"
8
+ class Phone
9
+ def initialize(phone_number)
10
+ @phone_number = phone_number
11
+ end
12
+
13
+ def to_s
14
+ "tel:#{@phone_number}"
15
+ end
16
+
17
+ #
18
+ # Validates that the passed phone number is in a valid format.
19
+ # @example
20
+ # valid phones:
21
+ # +919367788755
22
+ # 8989829304
23
+ # +16308520397
24
+ # 786-307-3615
25
+ # 555.555.5555
26
+ def validate!
27
+ # credit: https://ihateregex.io/expr/phone/
28
+ return if @phone_number =~ /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/
29
+
30
+ raise PayloadValidationError, "Invalid phone number format"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrForge
4
+ module Payloads
5
+ #
6
+ # Represents a plain text payload
7
+ # @example return "Hello, World!"
8
+ class PlainText
9
+ def initialize(text)
10
+ @text = text
11
+ end
12
+
13
+ def to_s
14
+ @text
15
+ end
16
+
17
+ #
18
+ # Validates that the passed data is a string.
19
+ def validate!
20
+ raise PayloadValidationError, "Must be a valid string" unless @text.is_a?(String)
21
+ raise PayloadValidationError, "String cannot be empty" if @text.empty?
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module QrForge
6
+ module Payloads
7
+ #
8
+ # Represents a URL payload
9
+ # @example return "https://example.com" or "http://example.com"
10
+ class Url
11
+ def initialize(url)
12
+ @url = url
13
+ end
14
+
15
+ def to_s
16
+ @url
17
+ end
18
+
19
+ #
20
+ # Validates that the passed url is a valid HTTP or HTTPS URL.
21
+ def validate!
22
+ uri = URI.parse(@url)
23
+
24
+ unless uri.is_a?(::URI::HTTP) || uri.is_a?(::URI::HTTPS)
25
+ raise PayloadValidationError, "Must be a valid HTTP/HTTPS URL"
26
+ end
27
+ rescue ::URI::InvalidURIError
28
+ raise PayloadValidationError, "Invalid URL syntax"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrForge
4
+ module Payloads
5
+ # Represents a Wi-Fi network payload
6
+ # @example returns WIFI:T:<encryption>;S:<ssid>;P:<password>;H:<hidden>;;
7
+ class Wifi
8
+ VALID_ENCRYPTIONS = %w[WEP WPA WPA2 WPA3].freeze
9
+ NO_PASSWORD_ENCRYPTION = "NOPASS"
10
+
11
+ def initialize(encryption:, ssid:, password: nil, hidden: false)
12
+ @encryption = encryption.upcase
13
+ @ssid = ssid
14
+ @password = password
15
+ @hidden = hidden
16
+ end
17
+
18
+ #
19
+ # Encryption type for the Wi-Fi network.
20
+ # @return [String, nil] The encryption type or nil if no password is set.
21
+ def encryption_type
22
+ "T:#{@encryption}" unless @encryption == NO_PASSWORD_ENCRYPTION
23
+ end
24
+
25
+ #
26
+ # SSID of the Wi-Fi network.
27
+ # @return [String] The SSID
28
+ def ssid
29
+ "S:#{escape(@ssid)}"
30
+ end
31
+
32
+ #
33
+ # Password for the Wi-Fi network.
34
+ # @return [String, nil] The password or nil if no password is set.
35
+ def password
36
+ "P:#{escape(@password)}" if @password && @encryption != NO_PASSWORD_ENCRYPTION
37
+ end
38
+
39
+ #
40
+ # Indicates if the Wi-Fi network is hidden
41
+ # @return [String, nil] "H:true" if hidden, nil otherwise
42
+ def hidden
43
+ "H:true" unless @hidden.nil? || @hidden == false
44
+ end
45
+
46
+ #
47
+ # Returns the parts of the Wi-Fi payload as an array.
48
+ # @return [Array<String>] The parts of the Wi-Fi payload
49
+ def parts
50
+ parts = []
51
+ parts << ssid
52
+ parts << encryption_type
53
+ parts << password
54
+ parts << hidden
55
+
56
+ parts.compact
57
+ end
58
+
59
+ def to_s
60
+ "WIFI:#{parts.join(";")};;"
61
+ end
62
+
63
+ #
64
+ # Validates the Wi-Fi payload data.
65
+ # @raise [PayloadValidationError] if the SSID is blank or if the password is required but not provided.
66
+ # @raise [PayloadValidationError] if the encryption type is invalid.
67
+ def validate!
68
+ raise PayloadValidationError, "SSID is required" if blank?(@ssid)
69
+
70
+ if @encryption != NO_PASSWORD_ENCRYPTION && blank?(@password)
71
+ raise PayloadValidationError, "Password is required for #{@encryption} networks"
72
+ end
73
+
74
+ return if VALID_ENCRYPTIONS.include?(@encryption) || @encryption == NO_PASSWORD_ENCRYPTION
75
+
76
+ raise PayloadValidationError, "Invalid encryption: #{@encryption}"
77
+ end
78
+
79
+ private
80
+
81
+ #
82
+ # Escapes special characters in the Wi-Fi payload.
83
+ # @param str [String, NilClass] The string to escape
84
+ # @return [String] The escaped string
85
+ def escape(str)
86
+ return "" if blank?(str)
87
+
88
+ # https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11
89
+ # Escape characters: \ ; , : " as they are valid in SSID but are used as delimiters in the payload format
90
+ str.to_s.gsub(/([\\;,:"])/) { "\\#{::Regexp.last_match(1)}" }
91
+ end
92
+
93
+ #
94
+ # Checks if a value is blank.
95
+ # @param val [String, nil] The value to check
96
+ # @return [Boolean] true if the value is blank, false otherwise
97
+ def blank?(val)
98
+ val.nil? || val.strip == ""
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrForge
4
+ module Payloads
5
+ class PayloadValidationError < StandardError; end
6
+ end
7
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rqrcode_core/qrcode"
3
+ require "rqrcode_core"
4
4
 
5
5
  module QrForge
6
6
  #
@@ -11,7 +11,7 @@ module QrForge
11
11
  attr_reader :modules, :version, :module_count, :quiet_zone
12
12
 
13
13
  def initialize(text:, version: 10, level: :h)
14
- qr = RQRCodeCore::QRCode.new(text, size: version, level: level)
14
+ qr = ::RQRCodeCore::QRCode.new(text, size: version, level: level)
15
15
  @version = qr.version
16
16
  @modules = qr.modules.map(&:dup)
17
17
  @module_count = @modules.size
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "nokogiri"
4
- require_relative "layout"
5
4
 
6
5
  module QrForge
7
6
  #
@@ -47,8 +46,7 @@ module QrForge
47
46
  @quiet_zone = 4
48
47
  @module_count = qr_data.module_count
49
48
  @image = config.dig(:design, :image)
50
- @width = config.dig(:design, :size)
51
- @height = config.dig(:design, :size)
49
+ @size = config.dig(:output, :size)
52
50
  @colors = DEFAULT_COLORS.merge(config.dig(:design, :colors) || {})
53
51
  @layout = QrForge::Layout.new(qr_data:, has_image: image_present?)
54
52
  end
@@ -58,10 +56,11 @@ module QrForge
58
56
  def to_svg
59
57
  Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
60
58
  xml.svg(
61
- width: @width || canvas_size,
62
- height: @height || canvas_size,
59
+ width: @size,
60
+ height: @size,
63
61
  xmlns: "http://www.w3.org/2000/svg",
64
- viewBox: "0 0 #{canvas_size} #{canvas_size}"
62
+ viewBox: "0 0 #{canvas_size} #{canvas_size}",
63
+ shape_rendering: "crispEdges"
65
64
  ) do
66
65
  draw_background(xml)
67
66
  draw_image(xml)
@@ -98,10 +97,10 @@ module QrForge
98
97
  def draw_image(xml)
99
98
  return unless image_present? && @qr_data.version >= 2
100
99
 
101
- image_range = @layout.image_area # a Range (row indices) for the image
100
+ image_range = @layout.image_area # row indices for the image
102
101
  size = image_range.size # width/height in modules
103
102
 
104
- # Convert module coords SVG coords (including quiet zone)
103
+ # Convert module coords to SVG coords (including quiet zone)
105
104
  x = image_range.first + @quiet_zone
106
105
  y = image_range.first + @quiet_zone
107
106
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QrForge
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.1"
5
5
  end
data/lib/qr_forge.rb CHANGED
@@ -1,7 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "zeitwerk"
4
- loader = Zeitwerk::Loader.for_gem
5
- loader.setup
6
4
 
7
- module QrForge;end
5
+ # Entry point for the QrForge gem.
6
+ module QrForge
7
+ def self.loader
8
+ @loader ||= Zeitwerk::Loader.for_gem.tap do |loader|
9
+ loader.tag = "qr_forge"
10
+ loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
11
+ loader.setup
12
+ end
13
+ end
14
+
15
+ loader
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qr_forge
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keegankb93
@@ -51,20 +51,6 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '2.0'
54
- - !ruby/object:Gem::Dependency
55
- name: vips
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '8.15'
61
- type: :runtime
62
- prerelease: false
63
- version_requirements: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '8.15'
68
54
  - !ruby/object:Gem::Dependency
69
55
  name: zeitwerk
70
56
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +102,13 @@ files:
116
102
  - lib/qr_forge/exporter.rb
117
103
  - lib/qr_forge/forge.rb
118
104
  - lib/qr_forge/layout.rb
105
+ - lib/qr_forge/payload.rb
106
+ - lib/qr_forge/payloads.rb
107
+ - lib/qr_forge/payloads/geo.rb
108
+ - lib/qr_forge/payloads/phone.rb
109
+ - lib/qr_forge/payloads/plain_text.rb
110
+ - lib/qr_forge/payloads/url.rb
111
+ - lib/qr_forge/payloads/wifi.rb
119
112
  - lib/qr_forge/qr_data.rb
120
113
  - lib/qr_forge/renderer.rb
121
114
  - lib/qr_forge/version.rb
@@ -126,6 +119,7 @@ metadata:
126
119
  homepage_uri: https://github.com/keegankb93/qr_forge
127
120
  source_code_uri: https://github.com/keegankb93/qr_forge
128
121
  changelog_uri: https://github.com/keegankb93/qr_forge/blob/main/CHANGELOG.md
122
+ rubygems_mfa_required: 'true'
129
123
  rdoc_options: []
130
124
  require_paths:
131
125
  - lib