mobility 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -2
- data/Gemfile.lock +34 -30
- data/README.md +104 -38
- data/lib/mobility/translates.rb +8 -8
- data/lib/mobility/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1cb9733fa29691f2e0097d9e500081919e132a0
|
4
|
+
data.tar.gz: e3a4a9ad74165350fd1cd331f2a794e1b2402c1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8968a7a6c8b73f8c9e588050c1d07fe5fc6145fff554d419ee1bfb5c1e284c3587ea221a7cb31bcddc6976e6bafea5a8f19738a6d6fd4e768720a49cf5f7aa90
|
7
|
+
data.tar.gz: efdd9d229d550a3fd09358e42e372aadb0f7df9e0372ca8e79f53996a33d55a13b866ec9c8dfd143f19d5ad078c2ab64d7353df8ac69b95113ee550d804d81f2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Mobility Changelog
|
2
2
|
|
3
|
-
## 0.1
|
3
|
+
## 0.1
|
4
4
|
|
5
|
-
|
5
|
+
### 0.1.3
|
6
|
+
|
7
|
+
* Add homepage to gemspec
|
8
|
+
* Pass backend class as context to `translates`
|
9
|
+
([adf93e3c6bb314b73fbd43b221819310a1407c4d](https://github.com/shioyama/mobility/commit/adf93e3c6bb314b73fbd43b221819310a1407c4d))
|
10
|
+
|
11
|
+
### 0.1.2
|
12
|
+
|
13
|
+
* Fix issues with querying in ActiveRecord jsonb and hstore backends
|
14
|
+
([527908d9317daee6bf91e3e1a188fb64365f7bab](https://github.com/shioyama/mobility/commit/527908d9317daee6bf91e3e1a188fb64365f7bab)
|
15
|
+
and
|
16
|
+
[5e6addd6f01cf255f5e71666324502ace96d3eac](https://github.com/shioyama/mobility/commit/5e6addd6f01cf255f5e71666324502ace96d3eac))
|
data/Gemfile.lock
CHANGED
@@ -1,42 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mobility (0.1.
|
4
|
+
mobility (0.1.2)
|
5
5
|
i18n (>= 0.6.10)
|
6
6
|
request_store (~> 1.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
actionpack (
|
12
|
-
actionview (=
|
13
|
-
activesupport (=
|
14
|
-
rack (~>
|
15
|
-
rack-test (~> 0.6.
|
16
|
-
rails-dom-testing (~>
|
11
|
+
actionpack (4.2.7.1)
|
12
|
+
actionview (= 4.2.7.1)
|
13
|
+
activesupport (= 4.2.7.1)
|
14
|
+
rack (~> 1.6)
|
15
|
+
rack-test (~> 0.6.2)
|
16
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
17
17
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
18
|
-
actionview (
|
19
|
-
activesupport (=
|
18
|
+
actionview (4.2.7.1)
|
19
|
+
activesupport (= 4.2.7.1)
|
20
20
|
builder (~> 3.1)
|
21
21
|
erubis (~> 2.7.0)
|
22
|
-
rails-dom-testing (~>
|
22
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
23
23
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
24
|
-
activemodel (
|
25
|
-
activesupport (=
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
activemodel (4.2.7.1)
|
25
|
+
activesupport (= 4.2.7.1)
|
26
|
+
builder (~> 3.1)
|
27
|
+
activerecord (4.2.7.1)
|
28
|
+
activemodel (= 4.2.7.1)
|
29
|
+
activesupport (= 4.2.7.1)
|
30
|
+
arel (~> 6.0)
|
31
|
+
activesupport (4.2.7.1)
|
32
32
|
i18n (~> 0.7)
|
33
|
+
json (~> 1.7, >= 1.7.7)
|
33
34
|
minitest (~> 5.1)
|
35
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
34
36
|
tzinfo (~> 1.1)
|
35
|
-
arel (
|
37
|
+
arel (6.0.4)
|
36
38
|
builder (3.2.3)
|
37
39
|
byebug (9.0.6)
|
38
40
|
coderay (1.1.1)
|
39
|
-
concurrent-ruby (1.0.4)
|
40
41
|
database_cleaner (1.5.3)
|
41
42
|
diff-lcs (1.3)
|
42
43
|
erubis (2.7.0)
|
@@ -60,6 +61,7 @@ GEM
|
|
60
61
|
guard-compat (~> 1.1)
|
61
62
|
rspec (>= 2.99.0, < 4.0)
|
62
63
|
i18n (0.7.0)
|
64
|
+
json (1.8.6)
|
63
65
|
listen (3.1.5)
|
64
66
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
65
67
|
rb-inotify (~> 0.9, >= 0.9.7)
|
@@ -72,7 +74,7 @@ GEM
|
|
72
74
|
minitest (5.10.1)
|
73
75
|
mysql2 (0.3.21)
|
74
76
|
nenv (0.3.0)
|
75
|
-
nokogiri (1.
|
77
|
+
nokogiri (1.6.8.1)
|
76
78
|
mini_portile2 (~> 2.1.0)
|
77
79
|
notiffany (0.1.1)
|
78
80
|
nenv (~> 0.1)
|
@@ -85,18 +87,20 @@ GEM
|
|
85
87
|
pry-byebug (3.4.2)
|
86
88
|
byebug (~> 9.0)
|
87
89
|
pry (~> 0.10)
|
88
|
-
rack (
|
90
|
+
rack (1.6.5)
|
89
91
|
rack-test (0.6.3)
|
90
92
|
rack (>= 1.0)
|
91
|
-
rails-
|
92
|
-
activesupport (>= 4.2.0
|
93
|
-
|
93
|
+
rails-deprecated_sanitizer (1.0.3)
|
94
|
+
activesupport (>= 4.2.0.alpha)
|
95
|
+
rails-dom-testing (1.0.7)
|
96
|
+
activesupport (>= 4.2.0.beta, < 5.0)
|
97
|
+
nokogiri (~> 1.6.0)
|
98
|
+
rails-deprecated_sanitizer (>= 1.0.1)
|
94
99
|
rails-html-sanitizer (1.0.3)
|
95
100
|
loofah (~> 2.0)
|
96
|
-
railties (
|
97
|
-
actionpack (=
|
98
|
-
activesupport (=
|
99
|
-
method_source
|
101
|
+
railties (4.2.7.1)
|
102
|
+
actionpack (= 4.2.7.1)
|
103
|
+
activesupport (= 4.2.7.1)
|
100
104
|
rake (>= 0.8.7)
|
101
105
|
thor (>= 0.18.1, < 2.0)
|
102
106
|
rake (10.5.0)
|
@@ -134,7 +138,7 @@ PLATFORMS
|
|
134
138
|
ruby
|
135
139
|
|
136
140
|
DEPENDENCIES
|
137
|
-
activerecord (>=
|
141
|
+
activerecord (>= 4.2.6, < 5.0)
|
138
142
|
bundler (~> 1.12)
|
139
143
|
database_cleaner (~> 1.5.3)
|
140
144
|
generator_spec (~> 0.9.3)
|
data/README.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
[gem]: https://rubygems.org/gems/mobility
|
2
|
+
[travis]: https://travis-ci.org/shioyama/mobility
|
3
|
+
[gemnasium]: https://gemnasium.com/shioyama/mobility
|
4
|
+
[codeclimate]: https://codeclimate.com/github/shioyama/mobility
|
5
|
+
|
1
6
|
# Mobility
|
2
|
-
![Build Status](https://travis-ci.org/shioyama/mobility.svg?branch=master)
|
3
7
|
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/mobility.svg)][gem]
|
9
|
+
[![Build Status](https://travis-ci.org/shioyama/mobility.svg?branch=master)][travis]
|
10
|
+
[![Dependency Status](https://gemnasium.com/shioyama/mobility.svg)][gemnasium]
|
11
|
+
[![Code Climate](https://codeclimate.com/github/shioyama/mobility/badges/gpa.svg)][codeclimate]
|
4
12
|
|
5
13
|
Mobility is a gem for storing and retrieving localized data through attributes
|
6
14
|
on a class. A variety of different storage strategies are supported through
|
@@ -39,18 +47,23 @@ features, including:
|
|
39
47
|
Add this line to your application's Gemfile:
|
40
48
|
|
41
49
|
```ruby
|
42
|
-
gem 'mobility', '~> 0.1.
|
50
|
+
gem 'mobility', '~> 0.1.3'
|
43
51
|
```
|
44
52
|
|
45
53
|
To translate attributes on a model, you must include (or extend) `Mobility`,
|
46
|
-
then call `translates`
|
47
|
-
options.
|
54
|
+
then call `translates` passing in one or more attributes as well as a hash of
|
55
|
+
options, including the backend to use. (See [Defining Backend
|
56
|
+
Attributes](#attributes) below.)
|
48
57
|
|
49
58
|
### ActiveRecord (Rails)
|
50
59
|
|
51
60
|
Requirements:
|
52
61
|
- ActiveRecord >= 5.0
|
53
62
|
|
63
|
+
(Support for some backends is also supported with ActiveRecord/Rails 4.2, see
|
64
|
+
the [active_record-4.2
|
65
|
+
branch](https://github.com/shioyama/mobility/tree/active_record_4.2).)
|
66
|
+
|
54
67
|
If using Mobility in a Rails project, you can run the generator to create an
|
55
68
|
initializer and (optionally) a migration to create shared tables for the
|
56
69
|
default key-value backend:
|
@@ -74,25 +87,36 @@ Mobility.config.default_backend = :key_value
|
|
74
87
|
```
|
75
88
|
|
76
89
|
To set a different default backend, set `default_backend` to another value (see
|
77
|
-
possibilities below). Other configuration options can be set using the
|
90
|
+
possibilities [below](#backend)). Other configuration options can be set using the
|
78
91
|
`configure` method, see: {Mobility::Configuration} for details.
|
79
92
|
|
80
|
-
|
81
|
-
|
82
|
-
following two lines:
|
93
|
+
To get started quickly, run the generator with tables, and add the following to
|
94
|
+
a class to add translated attributes:
|
83
95
|
|
84
96
|
```ruby
|
85
97
|
class Post < ActiveRecord::Base
|
86
|
-
|
87
|
-
translates :
|
88
|
-
translates :content, backend: :key_value, type: :text
|
98
|
+
translates :title, type: :string
|
99
|
+
translates :content, type: :content
|
89
100
|
end
|
90
101
|
```
|
91
102
|
|
92
|
-
You
|
93
|
-
|
94
|
-
|
95
|
-
|
103
|
+
You now have translated attributes `title` and `content` on the model:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
I18n.locale = :en
|
107
|
+
post = Post.create(title: "foo")
|
108
|
+
post.title #=> "Mobility"
|
109
|
+
I18n.locale = :ja
|
110
|
+
post.title #=> nil
|
111
|
+
post.title = "モビリティ"
|
112
|
+
post.save
|
113
|
+
post.title #=> "モビリティ"
|
114
|
+
I18n.locale = :en
|
115
|
+
post.title #=> "Mobility"
|
116
|
+
```
|
117
|
+
|
118
|
+
Congratulations! Now have a look at the [Usage](#usage) section to see what
|
119
|
+
else Mobility can do.
|
96
120
|
|
97
121
|
### Sequel
|
98
122
|
|
@@ -101,22 +125,65 @@ Requirements:
|
|
101
125
|
|
102
126
|
Essentially identical to ActiveRecord, with the exception that there is no
|
103
127
|
equivalent to a Rails generator (so you will need to create the migration for
|
104
|
-
|
128
|
+
any translation table(s) yourself, see the API docs for details).
|
105
129
|
|
106
|
-
|
130
|
+
## Usage
|
131
|
+
|
132
|
+
### <a name="attributes"></a>Defining Backend Attributes
|
133
|
+
|
134
|
+
In order to use Mobility on a class, you will need to `extend` the {Mobility}
|
135
|
+
module and call `translates`, passing in one or more attribute names as well as
|
136
|
+
a hash of options.
|
137
|
+
|
138
|
+
The options hash is used to generate the backend, and has several reserved keys:
|
139
|
+
|
140
|
+
- **`backend`** (Symbol or Class)<br>
|
141
|
+
The backend to use (defaults to the value of `Mobility.default_backend`). If
|
142
|
+
its value is a symbol it will be converted to CamelCase and appended to the
|
143
|
+
`Mobility::Backend` module name to get the backend class (so `key_value` will
|
144
|
+
be converted to {Mobility::Backend::KeyValue}). See the list of [backends](#backend).
|
145
|
+
- **`cache`** (Boolean)<br>
|
146
|
+
Whether to use a [cache](#cache).
|
147
|
+
- **`fallbacks`** (Boolean or Hash)<br>
|
148
|
+
Enable [fallbacks](#fallbacks), and optionally configure them.
|
149
|
+
- **`dirty`** (Boolean)<br>
|
150
|
+
Whether to enable [dirty tracking](#dirty).
|
151
|
+
- **`accessor_locales`** (Boolean or Array)<br>
|
152
|
+
Enable [locale accessors](#locale_accessors) and optionally configure them.
|
153
|
+
|
154
|
+
In addition to these, each backend may have specific configuration options. For
|
155
|
+
example, the default key-value backend, which stores attributes and their
|
156
|
+
translations as key/value pairs on shared tables, has a `type` option which
|
157
|
+
specifies which type of column (string or text) to use for storing
|
158
|
+
translations.
|
159
|
+
|
160
|
+
Here is an example defining three attributes on an ActiveRecord model:
|
107
161
|
|
108
162
|
```ruby
|
109
|
-
class Post <
|
163
|
+
class Post < ActiveRecord::Base
|
110
164
|
include Mobility
|
111
|
-
translates :title, :author, backend: :key_value, type: :string
|
112
|
-
translates :content, backend: :key_value, type: :text
|
165
|
+
translates :title, :author, backend: :key_value, type: :string, cache: false
|
166
|
+
translates :content, backend: :key_value, type: :text, fallbacks: true
|
113
167
|
end
|
114
168
|
```
|
115
169
|
|
116
|
-
|
117
|
-
|
170
|
+
`title`, `author` and `content` will use the `KeyValue` backend, which stores
|
171
|
+
translations on two shared translation tables (one for string-valued
|
172
|
+
translations and one for text-valued translations). The cache (enabled by
|
173
|
+
default) is disabled for `title` and `author` (but not `content`).
|
174
|
+
[Fallbacks](#fallbacks) are enabled for `content` (but not `title` or
|
175
|
+
`author`).
|
118
176
|
|
119
|
-
|
177
|
+
Finally, `title` and `author` store their translations as string columns
|
178
|
+
(`type: :string`) whereas `content` stores its values as text columns (`type:
|
179
|
+
:text`). The `type` key is a backend-specific option used by the `KeyValue`
|
180
|
+
backend.
|
181
|
+
|
182
|
+
Note that Mobility will detect the model class and use this to determine which
|
183
|
+
ORM-specific backend to use. In the example above, it will use
|
184
|
+
{Mobility::Backend::ActiveRecord::KeyValue}; if the class were a
|
185
|
+
`Sequel::Model`, it would have used {Mobility::Backend::Sequel::KeyValue}. In
|
186
|
+
general options to configure the backend are ORM-independent.
|
120
187
|
|
121
188
|
### Setting the Locale
|
122
189
|
|
@@ -232,35 +299,34 @@ backend ([below](#backend)).
|
|
232
299
|
|
233
300
|
Mobility supports six different (database) backends:
|
234
301
|
|
235
|
-
-
|
302
|
+
- **`:column`** ({Mobility::Backend::Column})<br>
|
236
303
|
Store translations as columns on a table with locale as a postfix, of the
|
237
304
|
form `title_en`, `title_fr`, etc. for an attribute `title`.
|
238
|
-
-
|
305
|
+
- **`:table`** ({Mobility::Backend::Table})<br>
|
239
306
|
Store translations on a model-specific table, e.g. for a model `Post` with
|
240
307
|
table `posts`, store translations on a table `post_translations`, and join
|
241
308
|
the translation table when fetching translated values.
|
242
|
-
-
|
309
|
+
- **`:key_value`** ({Mobility::Backend::KeyValue})<br>
|
243
310
|
Store translations on a shared table of locale/attribute translation pairs,
|
244
311
|
associated through a polymorphic relation with multiple models.
|
245
|
-
-
|
312
|
+
- **`:serialized`** ({Mobility::Backend::Serialized})<br>
|
246
313
|
Store translations as serialized YAML or JSON on a text column.
|
247
|
-
-
|
314
|
+
- **`:hstore`** ({Mobility::Backend::Hstore})<br>
|
248
315
|
Store translations as values of a hash stored as a PostgreSQL hstore column.
|
249
|
-
-
|
316
|
+
- **`:jsonb`** ({Mobility::Backend::Jsonb})<br>
|
250
317
|
Store translations as values of a hash stored as a PostgreSQL jsonb column.
|
251
318
|
|
252
319
|
Each backend has strengths and weaknesses. If you're unsure of which backend to
|
253
320
|
use, a rule of thumb would be:
|
254
321
|
|
255
|
-
- If you're using PostgreSQL as your database, use
|
322
|
+
- If you're using PostgreSQL as your database, use `:jsonb`.
|
256
323
|
- If you have a fixed, small set of locales that are not likely to increase,
|
257
|
-
and have a small number of models to translate, consider
|
258
|
-
{Mobility::Backend::Column}.
|
324
|
+
and have a small number of models to translate, consider `:column`.
|
259
325
|
- If you have a small set of models to be translated but translation to
|
260
|
-
potentially many different languages, consider
|
326
|
+
potentially many different languages, consider `:table`.
|
261
327
|
- For all other cases (many locales, many translated models), or if you're just
|
262
|
-
not sure, the recommended solution is
|
263
|
-
|
328
|
+
not sure, the recommended solution is `:key_value` for maximum flexibility
|
329
|
+
and minimum database migrations.
|
264
330
|
|
265
331
|
|
266
332
|
### <a name="locale-accessors"></a>Locale Accessors
|
@@ -501,7 +567,7 @@ To this end, Mobility backends strictly enforce the rule that *no backend
|
|
501
567
|
should modify a parent class in any way which would interfere with other
|
502
568
|
backends operating on the same class*. This is done using a heavy dose of
|
503
569
|
metaprogramming, details of which can be found in the [API
|
504
|
-
documentation](http://www.rubydoc.info/gems/mobility/0.1.
|
570
|
+
documentation](http://www.rubydoc.info/gems/mobility/0.1.3) and in the actual code.
|
505
571
|
|
506
572
|
In practice, this means that you can use different backends for different
|
507
573
|
attributes *on the same class* without any conflict, e.g. (assuming we
|
@@ -581,7 +647,7 @@ end
|
|
581
647
|
|
582
648
|
For details on how to define a backend class, see the {Mobility::Backend}
|
583
649
|
module and other classes defined in the [API
|
584
|
-
documentation](http://www.rubydoc.info/gems/mobility/0.1.
|
650
|
+
documentation](http://www.rubydoc.info/gems/mobility/0.1.3).
|
585
651
|
|
586
652
|
### Testing Backends
|
587
653
|
|
@@ -626,7 +692,7 @@ particular implementations.
|
|
626
692
|
## More Information
|
627
693
|
|
628
694
|
- [Github repository](https://www.github.com/shioyama/mobility)
|
629
|
-
- [API documentation](http://www.rubydoc.info/gems/mobility/0.1.
|
695
|
+
- [API documentation](http://www.rubydoc.info/gems/mobility/0.1.3)
|
630
696
|
|
631
697
|
## License
|
632
698
|
|
data/lib/mobility/translates.rb
CHANGED
@@ -7,14 +7,14 @@ passed to accessors to configure backend (see example below).
|
|
7
7
|
@example Defining backend on a class
|
8
8
|
class MyClass
|
9
9
|
extend Translates
|
10
|
-
mobility_accessor :foo,
|
10
|
+
mobility_accessor :foo, option: :value
|
11
11
|
end
|
12
12
|
|
13
13
|
@example Passing backend to a block
|
14
14
|
class MyClass
|
15
15
|
extend Translates
|
16
|
-
mobility_accessor :foo,
|
17
|
-
#
|
16
|
+
mobility_accessor :foo, option: :value do
|
17
|
+
# add custom code to backend class for this attribute only
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -44,25 +44,25 @@ passed to accessors to configure backend (see example below).
|
|
44
44
|
# Defines mobility accessor on model class.
|
45
45
|
# @param [Array<String>] attributes
|
46
46
|
# @param [Hash] options
|
47
|
-
# @yield
|
47
|
+
# @yield Yields to block with backend as context
|
48
48
|
# @!method mobility_accessor(*attributes, **options)
|
49
49
|
|
50
50
|
# Defines mobility reader and presence method on model class.
|
51
51
|
# @param [Array<String>] attributes
|
52
52
|
# @param [Hash] options
|
53
|
-
# @yield
|
53
|
+
# @yield Yields to block with backend as context
|
54
54
|
# @!method mobility_reader(*attributes, **options)
|
55
55
|
|
56
56
|
# Defines mobility writer on model class.
|
57
57
|
# @param [Array<String>] attributes
|
58
58
|
# @param [Hash] options
|
59
|
-
# @yield
|
59
|
+
# @yield Yields to block with backend as context
|
60
60
|
# @!method mobility_writer(*attributes, **options)
|
61
61
|
%w[accessor reader writer].each do |method|
|
62
62
|
class_eval <<-EOM, __FILE__, __LINE__ + 1
|
63
|
-
def mobility_#{method}(*args, **options)
|
63
|
+
def mobility_#{method}(*args, **options, &block)
|
64
64
|
attributes = Attributes.new(:#{method}, *args, options.merge(model_class: self))
|
65
|
-
|
65
|
+
attributes.backend.instance_eval &block if block_given?
|
66
66
|
attributes.each do |attribute|
|
67
67
|
alias_method "\#{attribute}_before_mobility", attribute if method_defined?(attribute) && #{%w[accessor reader].include? method}
|
68
68
|
alias_method "\#{attribute}_before_mobility=", "\#{attribute}=" if method_defined?("\#{attribute}=") && #{%w[accessor writer].include? method}
|
data/lib/mobility/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mobility
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Salzberg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: request_store
|
@@ -213,7 +213,7 @@ files:
|
|
213
213
|
- lib/mobility/translates.rb
|
214
214
|
- lib/mobility/version.rb
|
215
215
|
- lib/mobility/wrapper.rb
|
216
|
-
homepage:
|
216
|
+
homepage: https://github.com/shioyama/mobility
|
217
217
|
licenses:
|
218
218
|
- MIT
|
219
219
|
metadata: {}
|