rqrcode_core 0.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +12 -14
- data/.gitignore +1 -0
- data/CHANGELOG.md +44 -0
- data/Gemfile.lock +33 -4
- data/README.md +56 -21
- data/Rakefile +17 -8
- data/lib/rqrcode_core/qrcode/qr_8bit_byte.rb +4 -12
- data/lib/rqrcode_core/qrcode/qr_alphanumeric.rb +18 -25
- data/lib/rqrcode_core/qrcode/qr_bit_buffer.rb +14 -24
- data/lib/rqrcode_core/qrcode/qr_code.rb +210 -286
- data/lib/rqrcode_core/qrcode/qr_math.rb +9 -10
- data/lib/rqrcode_core/qrcode/qr_multi.rb +13 -0
- data/lib/rqrcode_core/qrcode/qr_numeric.rb +9 -20
- data/lib/rqrcode_core/qrcode/qr_polynomial.rb +15 -15
- data/lib/rqrcode_core/qrcode/qr_rs_block.rb +8 -10
- data/lib/rqrcode_core/qrcode/qr_segment.rb +61 -0
- data/lib/rqrcode_core/qrcode/qr_util.rb +48 -49
- data/lib/rqrcode_core/qrcode.rb +11 -9
- data/lib/rqrcode_core/version.rb +1 -1
- data/rqrcode_core.gemspec +17 -17
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea3856aba6c1bc5602b3f7fa4126187fe26c47fdba56447b709871f96f432ff5
|
4
|
+
data.tar.gz: eab7166c0e00478bcdb12ab6a550a9a9b595401bf5f6c0271c6bac95b722564f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9d1977c291eaed204644f09d3900b2ea18bde93e1c242628bdf1c4cd30573c046328e3cdbfe294c6ae27370f5963cdfa8454f1f2e6af7bf185e32cd0fefe592
|
7
|
+
data.tar.gz: 56d9c31b3c056a47ffccc2848f43e0e44d3b3a984f0ef4c332505fae31dadda0ca6adac5ad0566443dbf46a86a2b81b419806cf71a9da6880d51eacd583cbb34
|
data/.github/workflows/ruby.yml
CHANGED
@@ -10,22 +10,20 @@ on:
|
|
10
10
|
- master
|
11
11
|
|
12
12
|
jobs:
|
13
|
-
|
14
|
-
name: Test Ruby ${{ matrix.ruby_version }} on ${{ matrix.os }}
|
15
|
-
runs-on: ${{ matrix.os }}
|
13
|
+
Build:
|
16
14
|
strategy:
|
15
|
+
fail-fast: false
|
17
16
|
matrix:
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
os: [ubuntu-latest, macos-latest]
|
18
|
+
ruby: [2.5, 2.6, 2.7, 3.0]
|
19
|
+
runs-on: ${{ matrix.os }}
|
21
20
|
steps:
|
22
21
|
- uses: actions/checkout@v1
|
23
|
-
-
|
24
|
-
uses: actions/setup-ruby@v1
|
22
|
+
- uses: ruby/setup-ruby@v1
|
25
23
|
with:
|
26
|
-
ruby-version: ${{ matrix.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
25
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
26
|
+
- name: Run Tests
|
27
|
+
run: bundle exec rake test
|
28
|
+
- name: StandardRB Check
|
29
|
+
run: bundle exec standardrb --format progress
|
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [1.2.0] - 2021-08-26
|
11
|
+
|
12
|
+
- Added Multi Mode Support which allows for multi-segment encoding. Thanks to [@ssayer](https://github.com/ssayer)
|
13
|
+
|
14
|
+
## [1.1.0] - 2021-07-01
|
15
|
+
|
16
|
+
- Add a basic benchmark file
|
17
|
+
- Add standardRB badge
|
18
|
+
- Add `.freeze` on `CONST` lookup objects
|
19
|
+
- Remove unused `@mode` instance variable
|
20
|
+
- A batch of small refactors and optimizations
|
21
|
+
|
22
|
+
## [1.0.0] - 2021-04-23
|
23
|
+
|
24
|
+
### Changed
|
25
|
+
|
26
|
+
- README updated
|
27
|
+
- Small documentation clarification [@smnscp](https://github.com/smnscp).
|
28
|
+
- Rakefile cleaned up. You can now just run `rake` which will run specs and fix linting using `standardrb`
|
29
|
+
|
30
|
+
### Breaking Changes
|
31
|
+
|
32
|
+
- Very niche but a breaking change never the less. The `to_s` method *no longer* accepts the `:true` and `:false` arguments, but prefers `:dark` and `:light`.
|
33
|
+
|
34
|
+
## [0.2.0] - 2020-12-26
|
35
|
+
|
36
|
+
### Changed
|
37
|
+
|
38
|
+
- fix `required_ruby_version` for Ruby 3 support
|
39
|
+
|
40
|
+
[unreleased]: https://github.com/whomwah/rqrcode_core/compare/v1.2.0...HEAD
|
41
|
+
[1.2.0]: https://github.com/whomwah/rqrcode_core/compare/v1.1.0...v1.2.0
|
42
|
+
[1.1.0]: https://github.com/whomwah/rqrcode_core/compare/v1.0.0...v1.1.0
|
43
|
+
[1.0.0]: https://github.com/whomwah/rqrcode_core/compare/v0.2.0...v1.0.0
|
44
|
+
[0.2.0]: https://github.com/whomwah/rqrcode_core/compare/v0.1.2...v0.2.0
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,41 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rqrcode_core (
|
4
|
+
rqrcode_core (1.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
|
10
|
-
|
9
|
+
ast (2.4.2)
|
10
|
+
minitest (5.14.4)
|
11
|
+
parallel (1.20.1)
|
12
|
+
parser (3.0.2.0)
|
13
|
+
ast (~> 2.4.1)
|
14
|
+
rainbow (3.0.0)
|
15
|
+
rake (13.0.6)
|
16
|
+
regexp_parser (2.1.1)
|
17
|
+
rexml (3.2.5)
|
18
|
+
rubocop (1.18.4)
|
19
|
+
parallel (~> 1.10)
|
20
|
+
parser (>= 3.0.0.0)
|
21
|
+
rainbow (>= 2.2.2, < 4.0)
|
22
|
+
regexp_parser (>= 1.8, < 3.0)
|
23
|
+
rexml
|
24
|
+
rubocop-ast (>= 1.8.0, < 2.0)
|
25
|
+
ruby-progressbar (~> 1.7)
|
26
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
27
|
+
rubocop-ast (1.9.1)
|
28
|
+
parser (>= 3.0.1.1)
|
29
|
+
rubocop-performance (1.11.4)
|
30
|
+
rubocop (>= 1.7.0, < 2.0)
|
31
|
+
rubocop-ast (>= 0.4.0)
|
32
|
+
ruby-progressbar (1.11.0)
|
33
|
+
standard (1.1.7)
|
34
|
+
rubocop (= 1.18.4)
|
35
|
+
rubocop-performance (= 1.11.4)
|
36
|
+
standardrb (1.0.0)
|
37
|
+
standard
|
38
|
+
unicode-display_width (2.0.0)
|
11
39
|
|
12
40
|
PLATFORMS
|
13
41
|
ruby
|
@@ -17,6 +45,7 @@ DEPENDENCIES
|
|
17
45
|
minitest (~> 5.0)
|
18
46
|
rake (~> 13.0)
|
19
47
|
rqrcode_core!
|
48
|
+
standardrb (~> 1.0)
|
20
49
|
|
21
50
|
BUNDLED WITH
|
22
|
-
2.
|
51
|
+
2.2.22
|
data/README.md
CHANGED
@@ -1,24 +1,25 @@
|
|
1
|
-
![](https://github.com/whomwah/rqrcode_core/workflows/
|
1
|
+
![](https://github.com/whomwah/rqrcode_core/actions/workflows/ruby.yml/badge.svg)
|
2
|
+
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
2
3
|
|
3
4
|
# RQRCodeCore
|
4
5
|
|
5
|
-
`rqrcode_core` is a library for encoding QR
|
6
|
+
`rqrcode_core` is a library for encoding QR Codes in pure Ruby. It has a simple interface with all the standard qrcode options. It was originally adapted in 2008 from a Javascript library by [Kazuhiko Arase](https://github.com/kazuhikoarase).
|
6
7
|
|
7
8
|
Features:
|
8
9
|
|
9
|
-
* `rqrcode_core` is a
|
10
|
-
* It is an encoding library. You can't decode QR
|
11
|
-
* The interface is simple and assumes you just want to encode a string into a QR
|
12
|
-
* QR
|
10
|
+
* `rqrcode_core` is a Ruby only library. It requires no native libraries. Just Ruby!
|
11
|
+
* It is an encoding library. You can't decode QR Codes with it.
|
12
|
+
* The interface is simple and assumes you just want to encode a string into a QR Code, but also allows for encoding multiple segments.
|
13
|
+
* QR Code is trademarked by Denso Wave inc.
|
13
14
|
|
14
|
-
`rqrcode_core` is the basis of the popular `rqrcode` gem [https://github.com/whomwah/rqrcode]. This gem allows you to generate different renderings of your QR
|
15
|
+
`rqrcode_core` is the basis of the popular `rqrcode` gem [https://github.com/whomwah/rqrcode]. This gem allows you to generate different renderings of your QR Code, including `png`, `svg` and `ansi`.
|
15
16
|
|
16
17
|
## Installation
|
17
18
|
|
18
19
|
Add this line to your application's Gemfile:
|
19
20
|
|
20
21
|
```ruby
|
21
|
-
gem
|
22
|
+
gem "rqrcode_core"
|
22
23
|
```
|
23
24
|
|
24
25
|
And then execute:
|
@@ -32,8 +33,8 @@ Or install it yourself as:
|
|
32
33
|
## Basic Usage
|
33
34
|
|
34
35
|
```ruby
|
35
|
-
$ require
|
36
|
-
$ qr = RQRCodeCore::QRCode.new(
|
36
|
+
$ require "rqrcode_core"
|
37
|
+
$ qr = RQRCodeCore::QRCode.new("https://kyan.com")
|
37
38
|
$ puts qr.to_s
|
38
39
|
```
|
39
40
|
|
@@ -46,15 +47,24 @@ x xxx x xxxxx x xx x xxx x
|
|
46
47
|
... etc
|
47
48
|
```
|
48
49
|
|
50
|
+
## Multiple Encoding Support
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
$ require "rqrcode_core"
|
54
|
+
$ qr = RQRCodeCore::QRCode.new([{data: "byteencoded", mode: :byte_8bit}, {data: "A1" * 100, mode: :alphanumeric}, {data: "1" * 500, mode: :number}])
|
55
|
+
```
|
56
|
+
|
57
|
+
This will create a QR Code with byte encoded, alphanumeric and number segments. Any combination of encodings/segments will work provided it fits within size limits.
|
58
|
+
|
49
59
|
## Doing your own rendering
|
50
60
|
|
51
61
|
```ruby
|
52
|
-
require
|
62
|
+
require "rqrcode_core"
|
53
63
|
|
54
|
-
qr = RQRCodeCore::QRCode.new(
|
55
|
-
qr.
|
64
|
+
qr = RQRCodeCore::QRCode.new("https://kyan.com")
|
65
|
+
qr.rows.each do |row|
|
56
66
|
row.each do |col|
|
57
|
-
print col ?
|
67
|
+
print col ? "#" : " "
|
58
68
|
end
|
59
69
|
|
60
70
|
print "\n"
|
@@ -63,12 +73,14 @@ end
|
|
63
73
|
|
64
74
|
### Options
|
65
75
|
|
66
|
-
The library expects a string to be parsed in, other args are optional.
|
76
|
+
The library expects a string or array (for multiple encodings) to be parsed in, other args are optional.
|
67
77
|
|
68
78
|
```
|
69
|
-
|
79
|
+
data - the string or array you wish to encode
|
80
|
+
|
81
|
+
size - the size (integer) of the QR Code (defaults to smallest size needed to encode the string)
|
70
82
|
|
71
|
-
|
83
|
+
max_size - the max_size (Integer) of the QR Code (default RQRCodeCore::QRUtil.max_size)
|
72
84
|
|
73
85
|
level - the error correction level, can be:
|
74
86
|
* Level :l 7% of code can be restored
|
@@ -76,7 +88,7 @@ level - the error correction level, can be:
|
|
76
88
|
* Level :q 25% of code can be restored
|
77
89
|
* Level :h 30% of code can be restored (default :h)
|
78
90
|
|
79
|
-
mode
|
91
|
+
mode - the mode of the QR Code (defaults to alphanumeric or byte_8bit, depending on the input data, only used when data is a string):
|
80
92
|
* :number
|
81
93
|
* :alphanumeric
|
82
94
|
* :byte_8bit
|
@@ -85,13 +97,36 @@ mode - the mode of the qrcode (defaults to alphanumeric or byte_8bit, dependin
|
|
85
97
|
|
86
98
|
#### Example
|
87
99
|
|
88
|
-
```
|
89
|
-
|
100
|
+
```ruby
|
101
|
+
RQRCodeCore::QRCode.new("http://kyan.com", size: 1, level: :m, mode: :alphanumeric)
|
90
102
|
```
|
91
103
|
|
92
104
|
## Development
|
93
105
|
|
94
|
-
|
106
|
+
### Tests
|
107
|
+
|
108
|
+
You can run the test suite using:
|
109
|
+
|
110
|
+
```
|
111
|
+
$ ./bin/setup
|
112
|
+
$ rake
|
113
|
+
```
|
114
|
+
|
115
|
+
or try the project from the console with:
|
116
|
+
|
117
|
+
```
|
118
|
+
$ ./bin/console
|
119
|
+
```
|
120
|
+
|
121
|
+
### Linting
|
122
|
+
|
123
|
+
The project uses [standardrb](https://github.com/testdouble/standard) and can be run with:
|
124
|
+
|
125
|
+
```
|
126
|
+
$ ./bin/setup
|
127
|
+
$ rake standard # check
|
128
|
+
$ rake standard:fix # fix
|
129
|
+
```
|
95
130
|
|
96
131
|
## Contributing
|
97
132
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,19 @@
|
|
1
|
-
|
2
|
-
require "rake/testtask"
|
1
|
+
begin
|
2
|
+
require "rake/testtask"
|
3
|
+
require "standard/rake"
|
3
4
|
|
4
|
-
Rake::TestTask.new(:test) do |t|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.libs << "test"
|
7
|
+
t.libs << "lib"
|
8
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
9
|
+
end
|
10
|
+
|
11
|
+
task default: [:test, "standard:fix"]
|
9
12
|
|
10
|
-
|
13
|
+
desc "Run a simple benchmark (x1000)"
|
14
|
+
task :benchmark do
|
15
|
+
ruby "test/benchmark.rb"
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
# no standard/rspec available
|
19
|
+
end
|
@@ -2,21 +2,13 @@
|
|
2
2
|
|
3
3
|
module RQRCodeCore
|
4
4
|
class QR8bitByte
|
5
|
-
|
6
|
-
|
7
|
-
def initialize( data )
|
8
|
-
@mode = QRMODE[:mode_8bit_byte]
|
9
|
-
@data = data;
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
def get_length
|
14
|
-
@data.bytesize
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
15
7
|
end
|
16
8
|
|
9
|
+
def write(buffer)
|
10
|
+
buffer.byte_encoding_start(@data.bytesize)
|
17
11
|
|
18
|
-
def write( buffer)
|
19
|
-
buffer.byte_encoding_start(get_length)
|
20
12
|
@data.each_byte do |b|
|
21
13
|
buffer.put(b, 8)
|
22
14
|
end
|
@@ -1,43 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RQRCodeCore
|
4
|
-
ALPHANUMERIC = [
|
4
|
+
ALPHANUMERIC = [
|
5
|
+
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
|
6
|
+
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", " ", "$",
|
7
|
+
"%", "*", "+", "-", ".", "/", ":"
|
8
|
+
].freeze
|
5
9
|
|
6
10
|
class QRAlphanumeric
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
raise QRCodeArgumentError, "Not a alpha numeric uppercase string `#{data}`" unless QRAlphanumeric.valid_data?(data)
|
13
|
-
|
14
|
-
@data = data;
|
15
|
-
end
|
16
|
-
|
11
|
+
def initialize(data)
|
12
|
+
unless QRAlphanumeric.valid_data?(data)
|
13
|
+
raise QRCodeArgumentError, "Not a alpha numeric uppercase string `#{data}`"
|
14
|
+
end
|
17
15
|
|
18
|
-
|
19
|
-
@data.size
|
16
|
+
@data = data
|
20
17
|
end
|
21
18
|
|
22
|
-
def self.valid_data?
|
23
|
-
data.
|
24
|
-
return false if ALPHANUMERIC.index(s).nil?
|
25
|
-
end
|
26
|
-
true
|
19
|
+
def self.valid_data?(data)
|
20
|
+
(data.chars - ALPHANUMERIC).empty?
|
27
21
|
end
|
28
22
|
|
23
|
+
def write(buffer)
|
24
|
+
buffer.alphanumeric_encoding_start(@data.size)
|
29
25
|
|
30
|
-
|
31
|
-
buffer.alphanumeric_encoding_start(get_length)
|
32
|
-
|
33
|
-
(@data.size).times do |i|
|
26
|
+
@data.size.times do |i|
|
34
27
|
if i % 2 == 0
|
35
28
|
if i == (@data.size - 1)
|
36
29
|
value = ALPHANUMERIC.index(@data[i])
|
37
|
-
buffer.put(
|
30
|
+
buffer.put(value, 6)
|
38
31
|
else
|
39
|
-
value = (ALPHANUMERIC.index(@data[i]) * 45) + ALPHANUMERIC.index(@data[i+1])
|
40
|
-
buffer.put(
|
32
|
+
value = (ALPHANUMERIC.index(@data[i]) * 45) + ALPHANUMERIC.index(@data[i + 1])
|
33
|
+
buffer.put(value, 11)
|
41
34
|
end
|
42
35
|
end
|
43
36
|
end
|
@@ -13,74 +13,64 @@ module RQRCodeCore
|
|
13
13
|
@length = 0
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
def get( index )
|
16
|
+
def get(index)
|
18
17
|
buf_index = (index / 8).floor
|
19
|
-
((
|
18
|
+
((QRUtil.rszf(@buffer[buf_index], 7 - index % 8)) & 1) == 1
|
20
19
|
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
( 0...length ).each do |i|
|
21
|
+
def put(num, length)
|
22
|
+
(0...length).each do |i|
|
25
23
|
put_bit(((QRUtil.rszf(num, length - i - 1)) & 1) == 1)
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
|
-
|
30
27
|
def get_length_in_bits
|
31
28
|
@length
|
32
29
|
end
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
buf_index = ( @length / 8 ).floor
|
31
|
+
def put_bit(bit)
|
32
|
+
buf_index = (@length / 8).floor
|
37
33
|
if @buffer.size <= buf_index
|
38
34
|
@buffer << 0
|
39
35
|
end
|
40
36
|
|
41
37
|
if bit
|
42
|
-
@buffer[buf_index] |=
|
38
|
+
@buffer[buf_index] |= QRUtil.rszf(0x80, @length % 8)
|
43
39
|
end
|
44
40
|
|
45
41
|
@length += 1
|
46
42
|
end
|
47
43
|
|
48
44
|
def byte_encoding_start(length)
|
49
|
-
|
50
|
-
put( QRMODE[:mode_8bit_byte], 4 )
|
45
|
+
put(QRMODE[:mode_8bit_byte], 4)
|
51
46
|
put(length, QRUtil.get_length_in_bits(QRMODE[:mode_8bit_byte], @version))
|
52
|
-
|
53
47
|
end
|
54
48
|
|
55
49
|
def alphanumeric_encoding_start(length)
|
56
|
-
|
57
|
-
put( QRMODE[:mode_alpha_numk], 4 )
|
50
|
+
put(QRMODE[:mode_alpha_numk], 4)
|
58
51
|
put(length, QRUtil.get_length_in_bits(QRMODE[:mode_alpha_numk], @version))
|
59
|
-
|
60
52
|
end
|
61
53
|
|
62
54
|
def numeric_encoding_start(length)
|
63
|
-
|
64
|
-
put( QRMODE[:mode_number], 4 )
|
55
|
+
put(QRMODE[:mode_number], 4)
|
65
56
|
put(length, QRUtil.get_length_in_bits(QRMODE[:mode_number], @version))
|
66
|
-
|
67
57
|
end
|
68
58
|
|
69
59
|
def pad_until(prefered_size)
|
70
60
|
# Align on byte
|
71
61
|
while get_length_in_bits % 8 != 0
|
72
|
-
put_bit(
|
62
|
+
put_bit(false)
|
73
63
|
end
|
74
64
|
|
75
65
|
# Pad with padding code words
|
76
66
|
while get_length_in_bits < prefered_size
|
77
|
-
put(
|
78
|
-
put(
|
67
|
+
put(PAD0, 8)
|
68
|
+
put(PAD1, 8) if get_length_in_bits < prefered_size
|
79
69
|
end
|
80
70
|
end
|
81
71
|
|
82
72
|
def end_of_message(max_data_bits)
|
83
|
-
put(
|
73
|
+
put(0, 4) unless get_length_in_bits + 4 > max_data_bits
|
84
74
|
end
|
85
75
|
end
|
86
76
|
end
|