ires 0.2.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 +4 -4
- data/README.md +18 -9
- data/ext/Gopkg.lock +36 -2
- data/ext/ires/image.go +133 -103
- data/ext/ires/ires.go +91 -70
- data/ext/ires/uri.go +52 -62
- data/ext/main.go +24 -21
- data/lib/ires.rb +1 -1
- data/lib/ires/core.rb +9 -3
- data/lib/ires/mode.rb +7 -0
- data/lib/ires/os.rb +7 -9
- data/lib/ires/service.rb +12 -10
- data/lib/ires/type.rb +7 -0
- data/lib/ires/version.rb +1 -1
- data/lib/ires/view_helper.rb +12 -5
- data/lib/tasks/ires.rake +2 -2
- data/shared/darwin/ires.h +1 -1
- data/shared/darwin/ires.so +0 -0
- data/shared/linux/ires.h +15 -3
- data/shared/linux/ires.so +0 -0
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51c855f31ee4c3154e6f11d0c58e47b1f4b1e360
|
4
|
+
data.tar.gz: 9529a56c17f521b8cc669c5169d2416a02e96915
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74b58d89cb8f5062b1b1030d26f8ed4db13d298307cabab331b65e5294cc90e6665d4902d1f9775cfaecced305f63eb81d1ef47dff06aa5714d178f08171e3c8
|
7
|
+
data.tar.gz: 7a3d4a7eb98710e4ab36f17b96515e8449bb4ea5151de5ea325d3d48c956c83b95b31490aa07fa814b8840084eebb3b31ab1fabf626ad01008e33c55745b7af7
|
data/README.md
CHANGED
@@ -14,31 +14,40 @@
|
|
14
14
|
<%= ires_tag( path: "image_01.jpg", width: 90, height: 120 ) %>
|
15
15
|
|
16
16
|
<!-- Using image_tag options -->
|
17
|
-
<%= ires_tag( path: "http://example.com/image_02.jpg", width: 200, height: 200,
|
17
|
+
<%= ires_tag( path: "http://example.com/image_02.jpg", width: 200, height: 200, Ires::Mode::CROP, alt: "example image" ) %>
|
18
18
|
```
|
19
19
|
|
20
20
|
### Get resize path
|
21
21
|
|
22
22
|
```ruby
|
23
|
-
Ires::Service.path(
|
23
|
+
Ires::Service.path(path: '<FULL IMAGE PATH>', width: 400, height: 300)
|
24
24
|
=> /ires/<resize image path>
|
25
25
|
```
|
26
26
|
|
27
27
|
### Select mode
|
28
28
|
|
29
|
-
| info |
|
30
|
-
|
31
|
-
| Resize |
|
32
|
-
| Cropping |
|
33
|
-
| Rsize after Cropping |
|
29
|
+
| info | mode |
|
30
|
+
|:---------------------------|:---------------------------------|
|
31
|
+
| Resize | Ires::Mode::RESIZE (default) |
|
32
|
+
| Cropping | Ires::Mode::CROP |
|
33
|
+
| Rsize after Cropping | Ires::Mode::RESIZE_TO_CROP |
|
34
34
|
|
35
|
+
### Select type
|
36
|
+
|
37
|
+
Filter of resize image.
|
38
|
+
|
39
|
+
| info | type |
|
40
|
+
|:---------------------------|:---------------------------------|
|
41
|
+
| All | Ires::Type::ALL (default) |
|
42
|
+
| Smaller than | Ires::Type::SMALLER |
|
43
|
+
| Larger than | Ires::Type::LARGER |
|
35
44
|
|
36
45
|
### Specify cache expiration
|
37
46
|
|
38
47
|
Default: **30days**
|
39
48
|
|
40
49
|
```erb
|
41
|
-
<%= ires_tag( path:
|
50
|
+
<%= ires_tag( path: '/image.jpg', width: 400, height: 300, expire: 7.days ) %>
|
42
51
|
```
|
43
52
|
|
44
53
|
### Saved directory
|
@@ -117,7 +126,7 @@ $ dep ensure
|
|
117
126
|
# Output to a shared object.
|
118
127
|
$ CGO_ENABLED=1 GOOS=linux go build -v -buildmode=c-shared -o shared/linux/ires.so ext/main.go
|
119
128
|
```
|
120
|
-
※ In the current Docker, you can build only linux environment.
|
129
|
+
※ In the current Docker, you can build only linux environment.
|
121
130
|
※ If you want to build in other environments, add GCC or install Go on the host side.🙇
|
122
131
|
|
123
132
|
### 2. Start rails server
|
data/ext/Gopkg.lock
CHANGED
@@ -2,50 +2,84 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
[[projects]]
|
5
|
+
digest = "1:8e47871087b94913898333f37af26732faaab30cdb41571136cf7aec9921dae7"
|
5
6
|
name = "github.com/PuerkitoBio/purell"
|
6
7
|
packages = ["."]
|
8
|
+
pruneopts = ""
|
7
9
|
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
|
8
10
|
version = "v1.1.0"
|
9
11
|
|
10
12
|
[[projects]]
|
11
13
|
branch = "master"
|
14
|
+
digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c"
|
12
15
|
name = "github.com/PuerkitoBio/urlesc"
|
13
16
|
packages = ["."]
|
17
|
+
pruneopts = ""
|
14
18
|
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
15
19
|
|
16
20
|
[[projects]]
|
17
21
|
branch = "master"
|
22
|
+
digest = "1:690e87555de96973ac79aae9fe51fef5e470f7e3cde3b1aa731ae01ec3f9ffe8"
|
18
23
|
name = "github.com/goware/urlx"
|
19
24
|
packages = ["."]
|
25
|
+
pruneopts = ""
|
20
26
|
revision = "e22571dfbd216d3ca34207d9a1d877f38d8f051c"
|
21
27
|
|
22
28
|
[[projects]]
|
23
29
|
branch = "master"
|
30
|
+
digest = "1:74688aecdaaede7d4ea1ead4569dc5f9f8b169b3b9698470f8d107f347a7a2cd"
|
24
31
|
name = "github.com/nfnt/resize"
|
25
32
|
packages = ["."]
|
33
|
+
pruneopts = ""
|
26
34
|
revision = "891127d8d1b52734debe1b3c3d7e747502b6c366"
|
27
35
|
|
28
36
|
[[projects]]
|
37
|
+
digest = "1:8e8c82e661fc70a3dab1d1bb0f92b800ea32112f5926c08da9c13a46a57cc557"
|
29
38
|
name = "github.com/oliamb/cutter"
|
30
39
|
packages = ["."]
|
40
|
+
pruneopts = ""
|
31
41
|
revision = "5cd9c24de6524b7251ac6b8600b0ba8f43a85963"
|
32
42
|
version = "v0.2.0"
|
33
43
|
|
34
44
|
[[projects]]
|
35
45
|
branch = "master"
|
46
|
+
digest = "1:1418c6b5c10b5e07fb4c90a24227f6493e19ad4d31177d66458115fc47669fb5"
|
36
47
|
name = "golang.org/x/net"
|
37
48
|
packages = ["idna"]
|
49
|
+
pruneopts = ""
|
38
50
|
revision = "1087133bc4af3073e18add999345c6ae75918503"
|
39
51
|
|
40
52
|
[[projects]]
|
41
53
|
branch = "master"
|
54
|
+
digest = "1:706747bb1e3f870cf0dc52459cb94324cd347142fff3b61db56c0157a5f598d0"
|
42
55
|
name = "golang.org/x/text"
|
43
|
-
packages = [
|
56
|
+
packages = [
|
57
|
+
"collate",
|
58
|
+
"collate/build",
|
59
|
+
"internal/colltab",
|
60
|
+
"internal/gen",
|
61
|
+
"internal/tag",
|
62
|
+
"internal/triegen",
|
63
|
+
"internal/ucd",
|
64
|
+
"language",
|
65
|
+
"secure/bidirule",
|
66
|
+
"transform",
|
67
|
+
"unicode/bidi",
|
68
|
+
"unicode/cldr",
|
69
|
+
"unicode/norm",
|
70
|
+
"unicode/rangetable",
|
71
|
+
"width",
|
72
|
+
]
|
73
|
+
pruneopts = ""
|
44
74
|
revision = "c01e4764d870b77f8abe5096ee19ad20d80e8075"
|
45
75
|
|
46
76
|
[solve-meta]
|
47
77
|
analyzer-name = "dep"
|
48
78
|
analyzer-version = 1
|
49
|
-
|
79
|
+
input-imports = [
|
80
|
+
"github.com/goware/urlx",
|
81
|
+
"github.com/nfnt/resize",
|
82
|
+
"github.com/oliamb/cutter",
|
83
|
+
]
|
50
84
|
solver-name = "gps-cdcl"
|
51
85
|
solver-version = 1
|
data/ext/ires/image.go
CHANGED
@@ -1,57 +1,99 @@
|
|
1
1
|
package ires
|
2
2
|
|
3
3
|
import (
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
"bytes"
|
5
|
+
"image"
|
6
|
+
"image/gif"
|
7
|
+
"image/jpeg"
|
8
|
+
"image/png"
|
9
|
+
"io"
|
10
|
+
"io/ioutil"
|
11
|
+
"net/http"
|
12
|
+
"os"
|
13
|
+
"path"
|
14
|
+
"strings"
|
15
|
+
"time"
|
16
|
+
|
17
|
+
"github.com/nfnt/resize"
|
18
|
+
"github.com/oliamb/cutter"
|
18
19
|
)
|
19
20
|
|
21
|
+
// Check expiration date
|
22
|
+
func (i *Ires) DeleteExpireImage() {
|
23
|
+
today := time.Now().Format("20060102")
|
24
|
+
dir := i.readImageDir()
|
25
|
+
files, err := ioutil.ReadDir(dir)
|
26
|
+
if err != nil {
|
27
|
+
return
|
28
|
+
}
|
29
|
+
|
30
|
+
for _, file := range files {
|
31
|
+
findName := file.Name()
|
32
|
+
matched, _ := path.Match(today+"_*", findName)
|
33
|
+
if matched {
|
34
|
+
deleteImage(path.Join(dir, findName))
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
// Input image type is Local or HTTP
|
40
|
+
func (i *Ires) CheckLocal() {
|
41
|
+
if strings.Index(i.URI, "http") == -1 {
|
42
|
+
i.IsLocal = true
|
43
|
+
} else {
|
44
|
+
i.IsLocal = false
|
45
|
+
}
|
46
|
+
}
|
20
47
|
|
21
48
|
// Input image
|
22
|
-
func
|
49
|
+
func (i *Ires) inputImage() bool {
|
23
50
|
if i.IsLocal {
|
24
|
-
img, format := localImage(i.
|
25
|
-
|
26
|
-
|
27
|
-
|
51
|
+
img, format := localImage(i.URI)
|
52
|
+
i.InputImage = &InputImage{
|
53
|
+
Image: img,
|
54
|
+
Format: format,
|
55
|
+
URI: i.URI,
|
56
|
+
}
|
57
|
+
i.setConfig()
|
58
|
+
return true
|
28
59
|
}
|
60
|
+
return i.downloadImage()
|
29
61
|
}
|
30
62
|
|
31
|
-
|
32
63
|
// Save http image
|
33
|
-
func
|
34
|
-
res, err := http.Get(i.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
64
|
+
func (i *Ires) downloadImage() bool {
|
65
|
+
res, err := http.Get(i.URI)
|
66
|
+
if err != nil {
|
67
|
+
return false
|
68
|
+
}
|
69
|
+
defer res.Body.Close()
|
70
|
+
|
71
|
+
header, r := copyReader(res.Body)
|
72
|
+
format := formatSearch(r)
|
73
|
+
|
74
|
+
img, _, err := image.Decode(io.MultiReader(header, res.Body))
|
75
|
+
if err != nil {
|
76
|
+
return false
|
77
|
+
}
|
78
|
+
|
79
|
+
distURI := i.imageURI(true)
|
80
|
+
i.InputImage = &InputImage{
|
81
|
+
Image: img,
|
82
|
+
Format: format,
|
83
|
+
URI: distURI,
|
84
|
+
}
|
85
|
+
|
86
|
+
if createImage(img, distURI, format) {
|
87
|
+
i.setConfig()
|
88
|
+
return true
|
89
|
+
}
|
90
|
+
return false
|
48
91
|
}
|
49
92
|
|
50
|
-
|
51
|
-
func createImage(img image.Image, path, format string) image.Image {
|
93
|
+
func createImage(img image.Image, path, format string) bool {
|
52
94
|
file, err := os.Create(path)
|
53
95
|
if err != nil {
|
54
|
-
|
96
|
+
return false
|
55
97
|
}
|
56
98
|
defer file.Close()
|
57
99
|
|
@@ -65,15 +107,14 @@ func createImage(img image.Image, path, format string) image.Image {
|
|
65
107
|
default:
|
66
108
|
jpeg.Encode(file, img, nil)
|
67
109
|
}
|
68
|
-
return
|
110
|
+
return true
|
69
111
|
}
|
70
112
|
|
71
|
-
|
72
113
|
// Load image
|
73
114
|
func localImage(uri string) (image.Image, string) {
|
74
115
|
file, err := os.Open(uri)
|
75
|
-
if err != nil{
|
76
|
-
|
116
|
+
if err != nil {
|
117
|
+
return nil, ""
|
77
118
|
}
|
78
119
|
defer file.Close()
|
79
120
|
|
@@ -83,24 +124,33 @@ func localImage(uri string) (image.Image, string) {
|
|
83
124
|
|
84
125
|
img, _, err := image.Decode(io.MultiReader(header, file))
|
85
126
|
if err != nil {
|
86
|
-
|
127
|
+
return nil, ""
|
87
128
|
}
|
88
129
|
return img, format
|
89
130
|
}
|
90
131
|
|
132
|
+
// Set image config
|
133
|
+
func (i *Ires) setConfig() {
|
134
|
+
file, err := os.Open(i.InputImage.URI)
|
135
|
+
if err != nil {
|
136
|
+
panic(err)
|
137
|
+
}
|
138
|
+
defer file.Close()
|
139
|
+
|
140
|
+
conf, _, err := image.DecodeConfig(file)
|
141
|
+
if err != nil {
|
142
|
+
panic(err)
|
143
|
+
}
|
144
|
+
i.InputImage.Config = conf
|
145
|
+
}
|
91
146
|
|
92
147
|
// Resizing & Cropping
|
93
|
-
func
|
148
|
+
func (i *Ires) resizeToCrop() image.Image {
|
149
|
+
inputImg := i.InputImage.Image
|
94
150
|
var outputImg image.Image
|
95
|
-
|
96
|
-
if i.IsLocal {
|
97
|
-
imagePath = i.Uri
|
98
|
-
} else {
|
99
|
-
imagePath = i.imagePath(IMAGE_MODE_ORIGINAL)
|
100
|
-
}
|
101
|
-
isAsp, conf := isValidAspectRatio(imagePath, i.Size)
|
151
|
+
isAsp, conf := i.isValidAspectRatio()
|
102
152
|
|
103
|
-
width
|
153
|
+
width := i.Size.Width
|
104
154
|
height := i.Size.Height
|
105
155
|
|
106
156
|
if isAsp {
|
@@ -121,36 +171,15 @@ func resizeToCrop(i *Ires, inputImg image.Image) image.Image {
|
|
121
171
|
|
122
172
|
// Cropping
|
123
173
|
outputImg, _ = cutter.Crop(resizeImg, cutter.Config{
|
124
|
-
Width:
|
125
|
-
Height:
|
126
|
-
Mode:
|
174
|
+
Width: width,
|
175
|
+
Height: height,
|
176
|
+
Mode: cutter.Centered,
|
127
177
|
Options: cutter.Copy,
|
128
178
|
})
|
129
|
-
|
130
179
|
}
|
131
180
|
return outputImg
|
132
181
|
}
|
133
182
|
|
134
|
-
|
135
|
-
// Check expiration date
|
136
|
-
func (i *Ires) deleteExpireImage(mode int) {
|
137
|
-
today := time.Now().Format("20060102")
|
138
|
-
dir := i.readImageDir(mode)
|
139
|
-
files, err := ioutil.ReadDir(dir)
|
140
|
-
if err != nil {
|
141
|
-
return
|
142
|
-
}
|
143
|
-
|
144
|
-
for _, file := range files {
|
145
|
-
findName := file.Name()
|
146
|
-
matched,_ := path.Match(today + "_*", findName)
|
147
|
-
if matched {
|
148
|
-
deleteImage(path.Join(dir, findName))
|
149
|
-
}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
|
154
183
|
// Delete image
|
155
184
|
func deleteImage(path string) {
|
156
185
|
_, err := os.Stat(path)
|
@@ -161,38 +190,20 @@ func deleteImage(path string) {
|
|
161
190
|
}
|
162
191
|
}
|
163
192
|
|
164
|
-
|
165
193
|
// Verify aspect ratio
|
166
|
-
func
|
167
|
-
conf :=
|
194
|
+
func (i *Ires) isValidAspectRatio() (bool, image.Config) {
|
195
|
+
conf := i.InputImage.Config
|
196
|
+
s := i.Size
|
168
197
|
aspH := (conf.Height * s.Width) / conf.Width
|
169
198
|
if aspH == s.Height {
|
170
199
|
return true, conf
|
171
|
-
} else {
|
172
|
-
return false, conf
|
173
|
-
}
|
174
|
-
}
|
175
|
-
|
176
|
-
|
177
|
-
// Image config
|
178
|
-
func imageConfig(path string) image.Config {
|
179
|
-
file, err := os.Open(path)
|
180
|
-
if err != nil {
|
181
|
-
panic(err)
|
182
|
-
}
|
183
|
-
defer file.Close()
|
184
|
-
|
185
|
-
conf, _, err := image.DecodeConfig(file)
|
186
|
-
if err != nil {
|
187
|
-
panic(err)
|
188
200
|
}
|
189
|
-
return conf
|
201
|
+
return false, conf
|
190
202
|
}
|
191
203
|
|
192
|
-
|
193
204
|
// Select image resize mode
|
194
205
|
func resizeMode(conf image.Config, s Size) int {
|
195
|
-
srcWidth
|
206
|
+
srcWidth := s.Width
|
196
207
|
srcHeight := s.Height
|
197
208
|
|
198
209
|
if conf.Width >= conf.Height && srcWidth >= srcHeight {
|
@@ -207,10 +218,9 @@ func resizeMode(conf image.Config, s Size) int {
|
|
207
218
|
return 0
|
208
219
|
}
|
209
220
|
|
210
|
-
|
211
221
|
// Search image format
|
212
222
|
// if defined, return "jpeg"
|
213
|
-
func formatSearch(r io.Reader) string{
|
223
|
+
func formatSearch(r io.Reader) string {
|
214
224
|
_, format, err := image.DecodeConfig(r)
|
215
225
|
if err != nil {
|
216
226
|
return "jpeg"
|
@@ -218,10 +228,30 @@ func formatSearch(r io.Reader) string{
|
|
218
228
|
return format
|
219
229
|
}
|
220
230
|
|
221
|
-
|
222
231
|
// Copy Reader
|
223
232
|
func copyReader(body io.Reader) (io.Reader, io.Reader) {
|
224
233
|
header := bytes.NewBuffer(nil)
|
225
234
|
r := io.TeeReader(body, header)
|
226
235
|
return header, r
|
227
|
-
}
|
236
|
+
}
|
237
|
+
|
238
|
+
// Valid resize type
|
239
|
+
func (i *Ires) validResizeType() bool {
|
240
|
+
config := i.InputImage.Config
|
241
|
+
valid := false
|
242
|
+
switch i.ResizeType {
|
243
|
+
case All:
|
244
|
+
valid = true
|
245
|
+
case Smaller:
|
246
|
+
if config.Width < i.Width && config.Height < i.Height {
|
247
|
+
valid = true
|
248
|
+
}
|
249
|
+
case Larger:
|
250
|
+
if i.Width <= config.Width && i.Height <= config.Height {
|
251
|
+
valid = true
|
252
|
+
}
|
253
|
+
default:
|
254
|
+
valid = true
|
255
|
+
}
|
256
|
+
return valid
|
257
|
+
}
|
data/ext/ires/ires.go
CHANGED
@@ -1,102 +1,123 @@
|
|
1
1
|
package ires
|
2
2
|
|
3
3
|
import (
|
4
|
-
|
5
|
-
|
4
|
+
"image"
|
5
|
+
|
6
|
+
"github.com/nfnt/resize"
|
7
|
+
"github.com/oliamb/cutter"
|
6
8
|
)
|
7
9
|
|
10
|
+
type Mode int
|
8
11
|
const (
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
IMAGE_MODE_ORIGINAL
|
12
|
+
Resize Mode = iota
|
13
|
+
Crop
|
14
|
+
ResizeToCrop
|
13
15
|
)
|
14
16
|
|
15
|
-
type
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
Size
|
22
|
-
Dir string
|
23
|
-
Expire string
|
24
|
-
IsLocal bool
|
25
|
-
}
|
17
|
+
type ResizeType int
|
18
|
+
const (
|
19
|
+
All ResizeType = iota
|
20
|
+
Smaller
|
21
|
+
Larger
|
22
|
+
)
|
26
23
|
|
24
|
+
type (
|
25
|
+
// Size is ...
|
26
|
+
Size struct {
|
27
|
+
Width, Height int
|
28
|
+
}
|
29
|
+
|
30
|
+
// InputImage is ...
|
31
|
+
InputImage struct {
|
32
|
+
Image image.Image
|
33
|
+
Config image.Config
|
34
|
+
Format string
|
35
|
+
URI string
|
36
|
+
}
|
37
|
+
|
38
|
+
// Ires is ...
|
39
|
+
Ires struct {
|
40
|
+
Size
|
41
|
+
ResizeType
|
42
|
+
Mode
|
43
|
+
*InputImage
|
44
|
+
URI string
|
45
|
+
Dir string
|
46
|
+
Expire string
|
47
|
+
IsLocal bool
|
48
|
+
}
|
49
|
+
)
|
27
50
|
|
51
|
+
// Resize is ...
|
28
52
|
func (i *Ires) Resize() string {
|
29
|
-
|
30
|
-
i.
|
31
|
-
|
32
|
-
// Delete the expiration date image
|
33
|
-
i.deleteExpireImage(IMAGE_MODE_RESIZE)
|
34
|
-
|
35
|
-
distPath := i.imagePath(IMAGE_MODE_RESIZE)
|
53
|
+
i.Mode = Resize
|
54
|
+
distURI := i.imageURI(false)
|
36
55
|
// When the image exists, return the image path
|
37
|
-
if isExistsImage(
|
38
|
-
return i.
|
56
|
+
if isExistsImage(distURI) {
|
57
|
+
return i.targetImageURI(distURI)
|
39
58
|
}
|
40
59
|
|
41
|
-
|
42
|
-
|
43
|
-
return i.Uri
|
60
|
+
if !i.inputImage() {
|
61
|
+
return i.URI
|
44
62
|
}
|
45
63
|
|
46
|
-
outputImg
|
47
|
-
|
48
|
-
|
64
|
+
var outputImg image.Image
|
65
|
+
if i.validResizeType() {
|
66
|
+
outputImg = resize.Resize(uint(i.Width), uint(i.Height), i.InputImage.Image, resize.Lanczos3)
|
67
|
+
} else {
|
68
|
+
outputImg = i.InputImage.Image
|
69
|
+
}
|
70
|
+
createImage(outputImg, distURI, i.InputImage.Format)
|
71
|
+
return i.targetImageURI(distURI)
|
49
72
|
}
|
50
73
|
|
74
|
+
// Crop is Crop ...
|
51
75
|
func (i *Ires) Crop() string {
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
// Delete the expiration date image
|
56
|
-
i.deleteExpireImage(IMAGE_MODE_CROP)
|
57
|
-
|
58
|
-
distPath := i.imagePath(IMAGE_MODE_CROP)
|
76
|
+
i.Mode = Crop
|
77
|
+
distURI := i.imageURI(false)
|
59
78
|
// When the image exists, return the image path
|
60
|
-
if isExistsImage(
|
61
|
-
|
62
|
-
|
79
|
+
if isExistsImage(distURI) {
|
80
|
+
return i.targetImageURI(distURI)
|
81
|
+
}
|
63
82
|
|
64
|
-
|
65
|
-
|
66
|
-
return i.Uri
|
83
|
+
if !i.inputImage() {
|
84
|
+
return i.URI
|
67
85
|
}
|
68
86
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
87
|
+
var outputImg image.Image
|
88
|
+
if i.validResizeType() {
|
89
|
+
outputImg, _ = cutter.Crop(i.InputImage.Image, cutter.Config{
|
90
|
+
Width: i.Width,
|
91
|
+
Height: i.Height,
|
92
|
+
Mode: cutter.Centered,
|
93
|
+
Options: cutter.Copy,
|
94
|
+
})
|
95
|
+
} else {
|
96
|
+
outputImg = i.InputImage.Image
|
97
|
+
}
|
98
|
+
createImage(outputImg, distURI, i.InputImage.Format)
|
99
|
+
return i.targetImageURI(distURI)
|
78
100
|
}
|
79
101
|
|
102
|
+
// ResizeToCrop is ...
|
80
103
|
func (i *Ires) ResizeToCrop() string {
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
// Delete the expiration date image
|
85
|
-
i.deleteExpireImage(IMAGE_MODE_RESIZE_TO_CROP)
|
86
|
-
|
87
|
-
distPath := i.imagePath(IMAGE_MODE_RESIZE_TO_CROP)
|
104
|
+
i.Mode = ResizeToCrop
|
105
|
+
distURI := i.imageURI(false)
|
88
106
|
// When the image exists, return the image path
|
89
|
-
if isExistsImage(
|
90
|
-
return i.
|
107
|
+
if isExistsImage(distURI) {
|
108
|
+
return i.targetImageURI(distURI)
|
91
109
|
}
|
92
110
|
|
93
|
-
|
94
|
-
|
95
|
-
return i.Uri
|
111
|
+
if !i.inputImage() {
|
112
|
+
return i.URI
|
96
113
|
}
|
97
114
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
115
|
+
var outputImg image.Image
|
116
|
+
if i.validResizeType() {
|
117
|
+
outputImg = i.resizeToCrop()
|
118
|
+
} else {
|
119
|
+
outputImg = i.InputImage.Image
|
120
|
+
}
|
121
|
+
createImage(outputImg, distURI, i.InputImage.Format)
|
122
|
+
return i.targetImageURI(distURI)
|
102
123
|
}
|
data/ext/ires/uri.go
CHANGED
@@ -9,48 +9,8 @@ import (
|
|
9
9
|
"github.com/goware/urlx"
|
10
10
|
)
|
11
11
|
|
12
|
-
|
13
|
-
// Input image type is Local or HTTP
|
14
|
-
func (i *Ires) isLocalFile() {
|
15
|
-
if strings.Index(i.Uri, "http") == -1 {
|
16
|
-
i.IsLocal = true
|
17
|
-
} else {
|
18
|
-
i.IsLocal = false
|
19
|
-
}
|
20
|
-
}
|
21
|
-
|
22
|
-
|
23
|
-
// Generate image name
|
24
|
-
func imageName(i *Ires, mode int) string {
|
25
|
-
splitPath := strings.Split(i.Uri, "/")
|
26
|
-
|
27
|
-
// ex. sample.jpg
|
28
|
-
fileName := splitPath[len(splitPath)-1]
|
29
|
-
// ex. .jpg
|
30
|
-
ext := filepath.Ext(fileName)
|
31
|
-
|
32
|
-
name := strings.Replace(fileName, ext, "", 1)
|
33
|
-
|
34
|
-
extInfo := strings.Split(ext, "?")
|
35
|
-
if len(extInfo) > 1 {
|
36
|
-
ext = extInfo[0]
|
37
|
-
name += "_" + strings.Join(extInfo[1:], "")
|
38
|
-
}
|
39
|
-
|
40
|
-
var prefix string
|
41
|
-
switch mode {
|
42
|
-
case 0: prefix = prefixSize(i.Size) + "_resize"
|
43
|
-
case 1: prefix = prefixSize(i.Size) + "_crop"
|
44
|
-
case 2: prefix = prefixSize(i.Size) + "_resize_to_crop"
|
45
|
-
case 3: prefix = "original"
|
46
|
-
}
|
47
|
-
|
48
|
-
return i.Expire + "_" + name + "_" + prefix + ext
|
49
|
-
}
|
50
|
-
|
51
|
-
|
52
12
|
// Generate image path
|
53
|
-
func (i *Ires)
|
13
|
+
func (i *Ires) imageURI(original bool) string {
|
54
14
|
paths := []rune(i.Dir)
|
55
15
|
pathsLastIndex := len(paths) - 1
|
56
16
|
lastChar := string(paths[pathsLastIndex])
|
@@ -61,9 +21,9 @@ func (i *Ires) imagePath(mode int) string {
|
|
61
21
|
|
62
22
|
var oDir string
|
63
23
|
if i.IsLocal {
|
64
|
-
oDir = localPath(
|
24
|
+
oDir = localPath(i.Mode)
|
65
25
|
} else {
|
66
|
-
oDir = remotePath(i)
|
26
|
+
oDir = remotePath(i.URI)
|
67
27
|
}
|
68
28
|
|
69
29
|
// Create directory
|
@@ -74,10 +34,43 @@ func (i *Ires) imagePath(mode int) string {
|
|
74
34
|
}
|
75
35
|
}
|
76
36
|
|
77
|
-
name := imageName(
|
37
|
+
name := i.imageName(original)
|
78
38
|
return filepath.Join(oPath, name)
|
79
39
|
}
|
80
40
|
|
41
|
+
// Generate image name
|
42
|
+
func (i *Ires) imageName(original bool) string {
|
43
|
+
splitPath := strings.Split(i.URI, "/")
|
44
|
+
|
45
|
+
// ex. sample.jpg
|
46
|
+
fileName := splitPath[len(splitPath)-1]
|
47
|
+
// ex. .jpg
|
48
|
+
ext := filepath.Ext(fileName)
|
49
|
+
|
50
|
+
name := strings.Replace(fileName, ext, "", 1)
|
51
|
+
|
52
|
+
extInfo := strings.Split(ext, "?")
|
53
|
+
if len(extInfo) > 1 {
|
54
|
+
ext = extInfo[0]
|
55
|
+
name += "_" + strings.Join(extInfo[1:], "")
|
56
|
+
}
|
57
|
+
|
58
|
+
var prefix string
|
59
|
+
if original {
|
60
|
+
prefix = "original"
|
61
|
+
} else {
|
62
|
+
switch i.Mode {
|
63
|
+
case Resize:
|
64
|
+
prefix = prefixSize(i.Size) + "_resize"
|
65
|
+
case Crop:
|
66
|
+
prefix = prefixSize(i.Size) + "_crop"
|
67
|
+
case ResizeToCrop:
|
68
|
+
prefix = prefixSize(i.Size) + "_resize_to_crop"
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
return i.Expire + "_" + name + "_" + prefix + ext
|
73
|
+
}
|
81
74
|
|
82
75
|
// Create prefix by size
|
83
76
|
// ex. 640x480
|
@@ -85,45 +78,43 @@ func prefixSize(s Size) string {
|
|
85
78
|
return strconv.Itoa(s.Width) + "x" + strconv.Itoa(s.Height)
|
86
79
|
}
|
87
80
|
|
88
|
-
|
89
81
|
// リサイズ済みのファイルがあれば、処理せず返す
|
90
82
|
func isExistsImage(path string) bool {
|
91
83
|
_, err := os.Stat(path)
|
92
84
|
if err == nil {
|
93
85
|
return true
|
94
|
-
} else {
|
95
|
-
return false
|
96
86
|
}
|
87
|
+
return false
|
97
88
|
}
|
98
89
|
|
99
|
-
|
100
90
|
// Read directory
|
101
|
-
func (i *Ires) readImageDir(
|
91
|
+
func (i *Ires) readImageDir() string {
|
102
92
|
var dir string
|
103
93
|
if i.IsLocal {
|
104
|
-
dir = localPath(
|
94
|
+
dir = localPath(i.Mode)
|
105
95
|
} else {
|
106
|
-
dir = remotePath(i)
|
96
|
+
dir = remotePath(i.URI)
|
107
97
|
}
|
108
98
|
return filepath.Join(i.Dir, dir)
|
109
99
|
}
|
110
100
|
|
111
|
-
|
112
101
|
// if local image, create ires directory
|
113
|
-
func localPath(mode
|
102
|
+
func localPath(mode Mode) string {
|
114
103
|
var dir string
|
115
104
|
switch mode {
|
116
|
-
case
|
117
|
-
|
118
|
-
case
|
105
|
+
case Resize:
|
106
|
+
dir = "ires/resize"
|
107
|
+
case Crop:
|
108
|
+
dir = "ires/crop"
|
109
|
+
case ResizeToCrop:
|
110
|
+
dir = "ires/resize_to_crop"
|
119
111
|
}
|
120
112
|
return dir
|
121
113
|
}
|
122
114
|
|
123
|
-
|
124
115
|
// if http image, parse URL & make directory
|
125
|
-
func remotePath(
|
126
|
-
u, err := urlx.Parse(
|
116
|
+
func remotePath(uri string) string {
|
117
|
+
u, err := urlx.Parse(uri)
|
127
118
|
dir := []string{"ires"}
|
128
119
|
if err != nil {
|
129
120
|
panic(err)
|
@@ -136,8 +127,7 @@ func remotePath(i *Ires) string {
|
|
136
127
|
return strings.Join(dir, "/")
|
137
128
|
}
|
138
129
|
|
139
|
-
|
140
130
|
// Optimize image path
|
141
|
-
func (i *Ires)
|
142
|
-
return strings.Replace(
|
131
|
+
func (i *Ires) targetImageURI(uri string) string {
|
132
|
+
return strings.Replace(uri, i.Dir, "", -1)
|
143
133
|
}
|
data/ext/main.go
CHANGED
@@ -10,32 +10,35 @@ func init() {}
|
|
10
10
|
func main() {}
|
11
11
|
|
12
12
|
//export iresImagePath
|
13
|
-
func iresImagePath(
|
14
|
-
uri
|
15
|
-
|
16
|
-
|
17
|
-
expire := C.GoString(Expire)
|
13
|
+
func iresImagePath(URI *C.char, width, height, rType, mode int, Dir, Expire *C.char) *C.char {
|
14
|
+
uri := C.GoString(URI)
|
15
|
+
dir := C.GoString(Dir)
|
16
|
+
expire := C.GoString(Expire)
|
18
17
|
|
19
18
|
r := &ires.Ires{
|
20
|
-
Uri: uri,
|
21
19
|
Size: ires.Size{
|
22
|
-
Width:
|
20
|
+
Width: width,
|
23
21
|
Height: height,
|
24
22
|
},
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
ResizeType: ires.ResizeType(rType),
|
24
|
+
URI: uri,
|
25
|
+
Dir: dir,
|
26
|
+
Expire: expire,
|
28
27
|
}
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
case "crop":
|
35
|
-
imagePath = r.Crop()
|
36
|
-
case "resize_to_crop":
|
37
|
-
imagePath = r.ResizeToCrop()
|
38
|
-
}
|
29
|
+
// If local image, True
|
30
|
+
r.CheckLocal()
|
31
|
+
// Delete the expiration date image
|
32
|
+
r.DeleteExpireImage()
|
39
33
|
|
40
|
-
|
41
|
-
|
34
|
+
var distURI string
|
35
|
+
switch ires.Mode(mode) {
|
36
|
+
case ires.Resize:
|
37
|
+
distURI = r.Resize()
|
38
|
+
case ires.Crop:
|
39
|
+
distURI = r.Crop()
|
40
|
+
case ires.ResizeToCrop:
|
41
|
+
distURI = r.ResizeToCrop()
|
42
|
+
}
|
43
|
+
return C.CString(distURI)
|
44
|
+
}
|
data/lib/ires.rb
CHANGED
data/lib/ires/core.rb
CHANGED
@@ -4,11 +4,17 @@ require 'ires/os'
|
|
4
4
|
module Ires
|
5
5
|
module Core
|
6
6
|
extend FFI::Library
|
7
|
-
|
8
7
|
# NOTE: ires.so is golang object
|
9
8
|
ffi_lib File.expand_path("../../shared/#{Ires::Os.current}/ires.so", File.dirname(__FILE__))
|
10
|
-
|
11
9
|
# resize func
|
12
|
-
|
10
|
+
# Type:
|
11
|
+
# path: :string
|
12
|
+
# width: :int
|
13
|
+
# height: :int
|
14
|
+
# type: :int
|
15
|
+
# mode: :int
|
16
|
+
# dir: :string
|
17
|
+
# expire: :string
|
18
|
+
attach_function :iresImagePath, %i[string int int int int string string], :string
|
13
19
|
end
|
14
20
|
end
|
data/lib/ires/mode.rb
ADDED
data/lib/ires/os.rb
CHANGED
@@ -1,26 +1,25 @@
|
|
1
1
|
module Ires
|
2
2
|
module Os
|
3
3
|
class << self
|
4
|
-
|
5
4
|
# Reszie image directory
|
6
5
|
# @return [none(ffi)]
|
7
6
|
def current
|
8
|
-
if [
|
7
|
+
if %w[darwin linux].include?(os)
|
9
8
|
os
|
10
9
|
else
|
11
10
|
logger.fatal "Ires is not supported by this #{os}"
|
12
11
|
nil
|
13
12
|
end
|
14
13
|
end
|
15
|
-
|
16
|
-
private
|
14
|
+
|
15
|
+
private
|
17
16
|
|
18
17
|
# Search OS
|
19
18
|
# @return [String]
|
20
19
|
def os
|
21
|
-
@os ||=
|
22
|
-
|
23
|
-
|
20
|
+
@os ||= begin
|
21
|
+
host_os = RbConfig::CONFIG['host_os']
|
22
|
+
case host_os
|
24
23
|
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
25
24
|
'windows'
|
26
25
|
when /darwin|mac os/
|
@@ -31,10 +30,9 @@ module Ires
|
|
31
30
|
'unix'
|
32
31
|
else
|
33
32
|
'unknown'
|
33
|
+
end
|
34
34
|
end
|
35
|
-
)
|
36
35
|
end
|
37
|
-
|
38
36
|
end
|
39
37
|
end
|
40
38
|
end
|
data/lib/ires/service.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'ires/core'
|
2
2
|
require 'ires/os'
|
3
|
+
require 'ires/mode'
|
4
|
+
require 'ires/type'
|
3
5
|
|
4
6
|
module Ires
|
5
7
|
class Service
|
6
8
|
class << self
|
7
|
-
|
8
9
|
# Resize image path
|
9
10
|
# @return [String]
|
10
|
-
def path(path:, width:, height:, mode:
|
11
|
-
|
11
|
+
def path(path:, width:, height:, type: Type::ALL, mode: Mode::RESIZE, expire: 30.days)
|
12
12
|
os = Ires::Os.current
|
13
13
|
return nil if os.nil?
|
14
14
|
|
@@ -16,7 +16,7 @@ module Ires
|
|
16
16
|
|
17
17
|
# if no image or could not find file path then perform the same action as 'image_tag'
|
18
18
|
return nil if invalid_path?(full_path)
|
19
|
-
|
19
|
+
|
20
20
|
expiration_date = expiration_date(expire)
|
21
21
|
dir = image_dir
|
22
22
|
|
@@ -25,6 +25,7 @@ module Ires
|
|
25
25
|
width: width,
|
26
26
|
height: height,
|
27
27
|
mode: mode,
|
28
|
+
type: type,
|
28
29
|
dir: dir,
|
29
30
|
expire: expiration_date
|
30
31
|
}
|
@@ -53,28 +54,29 @@ module Ires
|
|
53
54
|
# Check file or URI
|
54
55
|
# @return [Bool]
|
55
56
|
def invalid_path?(path)
|
56
|
-
!File.exist?(path) && !path.include?(
|
57
|
+
!File.exist?(path) && !path.include?('http')
|
57
58
|
end
|
58
59
|
|
59
60
|
# Expiration date (default: 7.days)
|
60
61
|
# ex. "20170101"
|
61
62
|
# @return [String]
|
62
63
|
def expiration_date(expire)
|
63
|
-
(
|
64
|
+
(Time.zone.today + expire).strftime('%Y%m%d')
|
64
65
|
end
|
65
66
|
|
66
67
|
# Image path
|
67
68
|
# @return [String]
|
68
69
|
def ires_image_path(ires_element)
|
69
|
-
|
70
|
+
Core.iresImagePath(
|
70
71
|
ires_element[:path],
|
71
72
|
ires_element[:width],
|
72
73
|
ires_element[:height],
|
74
|
+
ires_element[:type],
|
73
75
|
ires_element[:mode],
|
74
76
|
ires_element[:dir],
|
75
|
-
ires_element[:expire]
|
77
|
+
ires_element[:expire]
|
78
|
+
)
|
76
79
|
end
|
77
|
-
|
78
80
|
end
|
79
81
|
end
|
80
|
-
end
|
82
|
+
end
|
data/lib/ires/type.rb
ADDED
data/lib/ires/version.rb
CHANGED
data/lib/ires/view_helper.rb
CHANGED
@@ -1,19 +1,26 @@
|
|
1
1
|
require 'ires/core'
|
2
2
|
require 'ires/service'
|
3
|
+
require 'ires/mode'
|
4
|
+
require 'ires/type'
|
3
5
|
require 'action_view/helpers'
|
4
6
|
|
5
7
|
module Ires
|
6
8
|
module ViewHelper
|
7
|
-
|
8
9
|
# Image resize
|
9
10
|
# @return [image_tag]
|
10
|
-
def ires_tag(path:, width:, height:, mode:
|
11
|
-
image = Ires::Service.path(
|
11
|
+
def ires_tag(path:, width:, height:, type: Type::ALL, mode: Mode::RESIZE, expire: 30.days, **option)
|
12
|
+
image = Ires::Service.path(
|
13
|
+
path: path,
|
14
|
+
width: width,
|
15
|
+
height: height,
|
16
|
+
mode: mode,
|
17
|
+
type: type,
|
18
|
+
expire: expire
|
19
|
+
)
|
12
20
|
return nil if image.nil?
|
13
21
|
|
14
22
|
# Set image_tag
|
15
23
|
image_tag(image, option)
|
16
24
|
end
|
17
|
-
|
18
25
|
end
|
19
|
-
end
|
26
|
+
end
|
data/lib/tasks/ires.rake
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'ires/os'
|
2
2
|
|
3
|
-
desc
|
3
|
+
desc 'Build shared object'
|
4
4
|
namespace :ires do
|
5
5
|
task :build do
|
6
6
|
os = Ires::Os.current
|
7
7
|
return if os.nil?
|
8
8
|
exec "CGO_ENABLED=1 GOOS=\"#{os}\" go build -v -buildmode=c-shared -o shared/\"#{os}\"/ires.so ext/main.go"
|
9
9
|
end
|
10
|
-
end
|
10
|
+
end
|
data/shared/darwin/ires.h
CHANGED
data/shared/darwin/ires.so
CHANGED
Binary file
|
data/shared/linux/ires.h
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
-
/*
|
1
|
+
/* Code generated by cmd/cgo; DO NOT EDIT. */
|
2
2
|
|
3
3
|
/* package command-line-arguments */
|
4
4
|
|
5
|
+
|
6
|
+
#line 1 "cgo-builtin-prolog"
|
7
|
+
|
8
|
+
#include <stddef.h> /* for ptrdiff_t below */
|
9
|
+
|
10
|
+
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
11
|
+
#define GO_CGO_EXPORT_PROLOGUE_H
|
12
|
+
|
13
|
+
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
14
|
+
|
15
|
+
#endif
|
16
|
+
|
5
17
|
/* Start of preamble from import "C" comments. */
|
6
18
|
|
7
19
|
|
@@ -38,7 +50,7 @@ typedef double _Complex GoComplex128;
|
|
38
50
|
*/
|
39
51
|
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
|
40
52
|
|
41
|
-
typedef
|
53
|
+
typedef _GoString_ GoString;
|
42
54
|
typedef void *GoMap;
|
43
55
|
typedef void *GoChan;
|
44
56
|
typedef struct { void *t; void *v; } GoInterface;
|
@@ -53,7 +65,7 @@ extern "C" {
|
|
53
65
|
#endif
|
54
66
|
|
55
67
|
|
56
|
-
extern char* iresImagePath(char* p0, GoInt p1, GoInt p2,
|
68
|
+
extern char* iresImagePath(char* p0, GoInt p1, GoInt p2, GoInt p3, GoInt p4, char* p5, char* p6);
|
57
69
|
|
58
70
|
#ifdef __cplusplus
|
59
71
|
}
|
data/shared/linux/ires.so
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ires
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- enta0701
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 4.1.8
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 4.1.8
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: ffi
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rails
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1112,8 +1112,10 @@ files:
|
|
1112
1112
|
- ext/vendor/golang.org/x/text/width/width.go
|
1113
1113
|
- lib/ires.rb
|
1114
1114
|
- lib/ires/core.rb
|
1115
|
+
- lib/ires/mode.rb
|
1115
1116
|
- lib/ires/os.rb
|
1116
1117
|
- lib/ires/service.rb
|
1118
|
+
- lib/ires/type.rb
|
1117
1119
|
- lib/ires/version.rb
|
1118
1120
|
- lib/ires/view_helper.rb
|
1119
1121
|
- lib/tasks/ires.rake
|