qr_forge 1.0.0 → 1.1.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 +4 -4
- data/README.md +176 -20
- data/lib/qr_forge/forge.rb +10 -6
- data/lib/qr_forge/payload.rb +39 -0
- data/lib/qr_forge/payloads/geo.rb +29 -0
- data/lib/qr_forge/payloads/phone.rb +35 -0
- data/lib/qr_forge/payloads/plain_text.rb +25 -0
- data/lib/qr_forge/payloads/url.rb +31 -0
- data/lib/qr_forge/payloads/wifi.rb +102 -0
- data/lib/qr_forge/payloads.rb +5 -0
- data/lib/qr_forge/version.rb +1 -1
- data/lib/qr_forge.rb +12 -3
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39cc8a8482cee2898925eab861d71d2a96e778d61d34e3e3e6d2774f8ec3fa95
|
4
|
+
data.tar.gz: d217725f654c5b08ee9e7addb7d04f04a8b7e9495b2809210c5ead98e933deb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc85e4a4f63070f81e69d2a7c715b17a9fccb5dd19469a4a72dd37ebfb40245b073b79e2a35357b5b0edfb73ca812f32be6651cf7afb496fc0af419093b87c9e
|
7
|
+
data.tar.gz: 48a38d7344bdc09748a0bd546a3466f4e403a90611ef85d40c6f9418cbf569f18b7c797d4dae346e8b192d14ed6ae836020bceddc51a855e1dc700b2dfa70540
|
data/README.md
CHANGED
@@ -1,39 +1,195 @@
|
|
1
|
-
#
|
1
|
+
# !! Docs are still being written !! #
|
2
|
+

|
2
3
|
|
3
|
-
|
4
|
+
An example of the output of QR Forge
|
4
5
|
|
5
|
-
|
6
|
+
# QR Forge
|
6
7
|
|
7
|
-
|
8
|
+
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
9
|
|
9
|
-
|
10
|
+
# Installation
|
10
11
|
|
11
|
-
|
12
|
+
```shell
|
13
|
+
gem install qr_forge
|
14
|
+
```
|
15
|
+
|
16
|
+
or if using bundler
|
17
|
+
|
18
|
+
```shell
|
19
|
+
bundle add qr_forge
|
20
|
+
```
|
21
|
+
|
22
|
+
Note: To export in the PNG format you will also want to install vips on your machine
|
12
23
|
|
13
|
-
```
|
14
|
-
|
24
|
+
```shell
|
25
|
+
brew install vips
|
15
26
|
```
|
16
27
|
|
17
|
-
|
28
|
+
# Usage
|
18
29
|
|
19
|
-
|
20
|
-
|
30
|
+
To create a QR Code you can simply do the following:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
QrForge::Forge.build(text: "https://yourlinkhere.com")
|
34
|
+
```
|
35
|
+
|
36
|
+
If you want an (SVG) QRCode fast, that's all there is to it. Everything else is covered by default values, however, you can tweak anything you want, which we will go through in the next section.
|
37
|
+
|
38
|
+
## Configuration
|
39
|
+
|
40
|
+
The library tries to provide sensible defaults, but defaults can be subjective, so the following shows a configuration object that you can pass to the QR Code.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
QrForge::Forge.build(
|
44
|
+
text: "https://www.google.com",
|
45
|
+
config: {
|
46
|
+
qr: { version: 10 },
|
47
|
+
components: { inner_eye: QrForge::Components::EyeInner::Square },
|
48
|
+
design: {
|
49
|
+
size: 800,
|
50
|
+
colors: { module: 'blue', outer_eye: 'cyan', inner_eye: 'skyblue' },
|
51
|
+
image: Base64.strict_encode64(...)
|
52
|
+
},
|
53
|
+
output: { format: :png }
|
54
|
+
}
|
55
|
+
)
|
21
56
|
```
|
22
57
|
|
23
|
-
|
58
|
+
##### QR
|
59
|
+
|
60
|
+
This hash provides details to the underlying QR code generator (see: https://github.com/whomwah/rqrcode_core).
|
61
|
+
|
62
|
+
_version_ dictates the module count or size of the QR Code and how much data it can hold. It does not necessarily dictate the dimensions, however, it will be unreadable if you choose too small of a size, but a larger QR code version. (see: https://www.qrcode.com/en/about/version.html)
|
24
63
|
|
25
|
-
|
64
|
+
##### Components
|
26
65
|
|
27
|
-
|
66
|
+
This hash can have up to 3 components:
|
67
|
+
- outer_eye
|
68
|
+
<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" />
|
28
69
|
|
29
|
-
|
70
|
+
- inner_eye
|
71
|
+
<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" />
|
30
72
|
|
31
|
-
|
73
|
+
- module
|
74
|
+
<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" />
|
32
75
|
|
33
|
-
|
76
|
+
This is what the circle outer_eye component looks like:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
# frozen_string_literal: true
|
80
|
+
|
81
|
+
module QrForge
|
82
|
+
module Components
|
83
|
+
module EyeOuter
|
84
|
+
class Circle < ForgeComponent
|
85
|
+
DEFAULT_STROKE_WIDTH = 1.0
|
86
|
+
|
87
|
+
# @see ForgeComponent#draw
|
88
|
+
# Draws a circle that fills the full 'area' box, inset by half the stroke so it
|
89
|
+
# never overlaps the modules beneath.
|
90
|
+
def draw(y:, x:, quiet_zone:, area:, color: "black", **_)
|
91
|
+
stroke_width = DEFAULT_STROKE_WIDTH
|
92
|
+
|
93
|
+
# Radius = (full width of box – one stroke) / 2
|
94
|
+
r = (area - stroke_width) / 2.0
|
95
|
+
|
96
|
+
# Center of the N×N box (plus quiet_zone offset)
|
97
|
+
cx = x + quiet_zone + (area / 2.0)
|
98
|
+
cy = y + quiet_zone + (area / 2.0)
|
99
|
+
|
100
|
+
@xml_builder.circle(
|
101
|
+
cx: cx,
|
102
|
+
cy: cy,
|
103
|
+
r: r,
|
104
|
+
'stroke-width': stroke_width,
|
105
|
+
stroke: color,
|
106
|
+
fill: "transparent",
|
107
|
+
test_id: @test_id
|
108
|
+
)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
And the square for comparison:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
# frozen_string_literal: true
|
120
|
+
|
121
|
+
module QrForge
|
122
|
+
module Components
|
123
|
+
module EyeOuter
|
124
|
+
class Square < ForgeComponent
|
125
|
+
# @see ForgeComponent#draw
|
126
|
+
def draw(y:, x:, quiet_zone:, area:, color: "black", **_)
|
127
|
+
x += quiet_zone
|
128
|
+
y += quiet_zone
|
129
|
+
|
130
|
+
# Draw the outer black square (7x7)
|
131
|
+
@xml_builder.rect(
|
132
|
+
x:,
|
133
|
+
y:,
|
134
|
+
width: area,
|
135
|
+
height: area,
|
136
|
+
fill: color
|
137
|
+
)
|
138
|
+
|
139
|
+
# Draw the inner (cutout) square (5x5) to create the finder pattern
|
140
|
+
inset = 1
|
141
|
+
inner = area - 2
|
142
|
+
|
143
|
+
@xml_builder.rect(
|
144
|
+
x: x + inset,
|
145
|
+
y: y + inset,
|
146
|
+
width: inner,
|
147
|
+
height: inner,
|
148
|
+
fill: color,
|
149
|
+
test_id: @test_id
|
150
|
+
)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
All components must inherit from the base ForgeComponent. You can look at that to see what is available to be used (this is on the roadmap to allow more design variations).
|
159
|
+
|
160
|
+
If you create your own designs, follow the same pattern and pass them into the components 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!
|
161
|
+
|
162
|
+
##### Design
|
163
|
+
|
164
|
+
```
|
165
|
+
size: 800
|
166
|
+
```
|
167
|
+
|
168
|
+
This sets the width and height of the svg. I recommend that you set this to a higher value than you plan to use as the SVG will scale well without needing to use any image processing like vips. If you do want to use your own strategies for image processing, I still recommend a higher size and do with the SVG as you wish.
|
169
|
+
|
170
|
+
```
|
171
|
+
colors: { module: 'blue', outer_eye: 'cyan', inner_eye: 'skyblue' }
|
172
|
+
```
|
173
|
+
|
174
|
+
This will set the fill or stroke appropriately for the respective component.
|
175
|
+
|
176
|
+
```
|
177
|
+
image: ...
|
178
|
+
```
|
179
|
+
|
180
|
+
A base64 encoded image that will be placed in the center of your QR Code. This scales with the version of the QR Code and is strictly set as to make sure that we do not remove more data that can be recovered through the error correcting algorithms.
|
181
|
+
|
182
|
+
##### Output
|
183
|
+
|
184
|
+
```
|
185
|
+
output: { format: :png }})
|
186
|
+
```
|
34
187
|
|
35
|
-
|
188
|
+
This will use vips to process the svg and return it as a PNG. If you want to do your own image processing, you can leave this off as the default is the raw SVG string.
|
36
189
|
|
37
|
-
## License
|
38
190
|
|
39
|
-
|
191
|
+
## Roadmap
|
192
|
+
- Color gradients for components
|
193
|
+
- More data types i.e. wifi, passkey etc.
|
194
|
+
- Image background and shape improvements
|
195
|
+
- More default component selections
|
data/lib/qr_forge/forge.rb
CHANGED
@@ -4,21 +4,25 @@ module QrForge
|
|
4
4
|
#
|
5
5
|
# Entry point for building QRCodes
|
6
6
|
class Forge
|
7
|
-
def initialize(
|
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
|
18
|
-
# @param
|
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).
|
19
23
|
# @return [String, StringIO] The SVG or PNG representation of the QR code
|
20
|
-
def self.build(
|
21
|
-
new(
|
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,39 @@
|
|
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
|
+
PAYLOAD_TYPES = {
|
9
|
+
wifi: ::QrForge::Payloads::Wifi,
|
10
|
+
plain: ::QrForge::Payloads::PlainText,
|
11
|
+
url: ::QrForge::Payloads::Url,
|
12
|
+
geo: ::QrForge::Payloads::Geo,
|
13
|
+
phone: ::QrForge::Payloads::Phone
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
#
|
17
|
+
# Builds a payload based on the type and data provided.
|
18
|
+
# @param type [Symbol] The type of payload to build (e.g., :url, :wifi).
|
19
|
+
# @param data [String, Hash] The data to encode in the payload.
|
20
|
+
# @return [String] The string representation of the payload.
|
21
|
+
def self.build(type:, data:)
|
22
|
+
klass = PAYLOAD_TYPES[type.to_sym]
|
23
|
+
|
24
|
+
raise ArgumentError "Invalid payload type: #{type}" unless klass
|
25
|
+
|
26
|
+
payload = case data
|
27
|
+
when Hash
|
28
|
+
klass.new(**data)
|
29
|
+
when String
|
30
|
+
klass.new(data)
|
31
|
+
else
|
32
|
+
raise ArgumentError, "Invalid data type: #{data.class}. Expected Hash or String."
|
33
|
+
end
|
34
|
+
|
35
|
+
payload.validate!
|
36
|
+
payload
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
puts "[Geo] file loaded"
|
4
|
+
|
5
|
+
module QrForge
|
6
|
+
module Payloads
|
7
|
+
#
|
8
|
+
# Represents a geo lat/long payload
|
9
|
+
# @example return "geo:40.712776,-74.005974"
|
10
|
+
class Geo
|
11
|
+
def initialize(latitude:, longitude:)
|
12
|
+
@latitude = latitude
|
13
|
+
@longitude = longitude
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"geo:#{@latitude},#{@longitude}"
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Validates that the passed latitude and longitude are within valid ranges.
|
22
|
+
def validate!
|
23
|
+
return if (-90..90).cover?(@latitude.to_f) && (-180..180).cover?(@longitude.to_f)
|
24
|
+
|
25
|
+
raise PayloadValidationError, "Latitude or longitude out of range"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'uri'
|
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
|
+
|
10
|
+
def initialize(phone_number)
|
11
|
+
@phone_number = phone_number
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"tel:#{@phone_number}"
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Validates that the passed phone number is in a valid format.
|
20
|
+
# @example
|
21
|
+
# valid phones:
|
22
|
+
# +919367788755
|
23
|
+
# 8989829304
|
24
|
+
# +16308520397
|
25
|
+
# 786-307-3615
|
26
|
+
# 555.555.5555
|
27
|
+
def validate!
|
28
|
+
# credit: https://ihateregex.io/expr/phone/
|
29
|
+
return if @phone_number =~ /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/
|
30
|
+
|
31
|
+
raise PayloadValidationError, "Invalid phone number format"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
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,31 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module QrForge
|
4
|
+
module Payloads
|
5
|
+
#
|
6
|
+
# Represents a URL payload
|
7
|
+
# @example return "https://example.com" or "http://example.com"
|
8
|
+
class Url
|
9
|
+
|
10
|
+
def initialize(url)
|
11
|
+
@url = url
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@url
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Validates that the passed url is a valid HTTP or HTTPS URL.
|
20
|
+
def validate!
|
21
|
+
uri = URI.parse(@url)
|
22
|
+
|
23
|
+
unless uri.is_a?(::URI::HTTP) || uri.is_a?(::URI::HTTPS)
|
24
|
+
raise PayloadValidationError, "Must be a valid HTTP/HTTPS URL"
|
25
|
+
end
|
26
|
+
rescue ::URI::InvalidURIError
|
27
|
+
raise PayloadValidationError, "Invalid URL syntax"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
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
|
data/lib/qr_forge/version.rb
CHANGED
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
|
-
|
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.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keegankb93
|
@@ -116,6 +116,13 @@ files:
|
|
116
116
|
- lib/qr_forge/exporter.rb
|
117
117
|
- lib/qr_forge/forge.rb
|
118
118
|
- lib/qr_forge/layout.rb
|
119
|
+
- lib/qr_forge/payload.rb
|
120
|
+
- lib/qr_forge/payloads.rb
|
121
|
+
- lib/qr_forge/payloads/geo.rb
|
122
|
+
- lib/qr_forge/payloads/phone.rb
|
123
|
+
- lib/qr_forge/payloads/plain_text.rb
|
124
|
+
- lib/qr_forge/payloads/url.rb
|
125
|
+
- lib/qr_forge/payloads/wifi.rb
|
119
126
|
- lib/qr_forge/qr_data.rb
|
120
127
|
- lib/qr_forge/renderer.rb
|
121
128
|
- lib/qr_forge/version.rb
|