natural_born_slugger 0.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 +7 -0
- data/.gitignore +17 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.md +24 -0
- data/README.md +182 -0
- data/Rakefile +1 -0
- data/lib/natural_born_slugger/class_methods.rb +101 -0
- data/lib/natural_born_slugger/configuration.rb +12 -0
- data/lib/natural_born_slugger/exceptions.rb +29 -0
- data/lib/natural_born_slugger/extensions/string.rb +10 -0
- data/lib/natural_born_slugger/instance_methods.rb +33 -0
- data/lib/natural_born_slugger/version.rb +3 -0
- data/lib/natural_born_slugger.rb +33 -0
- data/natural_born_slugger.gemspec +28 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c53161bfaee3307f0789e14966a1cef3def933f3
|
4
|
+
data.tar.gz: b0d8d1d8e94fae0798e5ad1b6411d21ff50a18c0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4847802082fabbcb6f537d607f8cabf918fda7a258966c4ac0b43e9a7fe7a89794f1880a2b1a9918c800a80c1d9ab23c3fb15d2f0fca151b32eb6a5e1d443390
|
7
|
+
data.tar.gz: b93c87ae94fec058f6dac6e6027cc5dde19ab2880a7d292dfd89f5eeca71cada422cc8fbc326a3acfb3755789c5469716190bc7ac0167d943ad2d063ead921fc
|
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
- LICENSE.md
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
MIT License
|
2
|
+
===========
|
3
|
+
|
4
|
+
Copyright (c) 2013 Christopher Keele
|
5
|
+
------------------------------------
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
Natural Born Slugger
|
2
|
+
====================
|
3
|
+
|
4
|
+
A gem for managing composite attributes, especially natural keys and url slugs.
|
5
|
+
|
6
|
+
Supports automatically-updated natural keys/slugs. Has ORM and Rack extensions.
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
Installation
|
11
|
+
------------
|
12
|
+
|
13
|
+
Using bundler, add to your `Gemfile`:
|
14
|
+
|
15
|
+
gem 'natural_born_slugger'
|
16
|
+
|
17
|
+
Otherwise:
|
18
|
+
|
19
|
+
gem install natural_born_slugger
|
20
|
+
|
21
|
+
and load it:
|
22
|
+
|
23
|
+
require 'natural_born_slugger'
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
Usage
|
28
|
+
-----
|
29
|
+
|
30
|
+
### Composing Attributes
|
31
|
+
|
32
|
+
At its core, `NaturalBornSlugger` is a simple, well-tested DSL to compose dynamic attributes dependent on other fields:
|
33
|
+
|
34
|
+
Person = Struct.new(:first_name, :middle_name, :last_name) do
|
35
|
+
include NaturalBornSlugger
|
36
|
+
has_slug first_name: nil, middle_name: nil, last_name: nil
|
37
|
+
end
|
38
|
+
|
39
|
+
bambino = Person.new('George', 'Herman', 'Ruth')
|
40
|
+
|
41
|
+
bambino.slug #=> "GeorgeHermanRuth"
|
42
|
+
|
43
|
+
bambino.first_name, bambino.middle_name = 'Babe', nil
|
44
|
+
|
45
|
+
bambino.slug #=> "BabeRuth"
|
46
|
+
|
47
|
+
|
48
|
+
### Setting Transformations
|
49
|
+
|
50
|
+
`NaturalBornSlugger` also lets you set tranformations on each dependency:
|
51
|
+
|
52
|
+
Person = Struct.new(:id, :name) do
|
53
|
+
include NaturalBornSlugger
|
54
|
+
has_natural_key name: :dashify, id: :hashify, join_with: '-'
|
55
|
+
end
|
56
|
+
|
57
|
+
buster = Person.new(23, 'Lou Gehrig')
|
58
|
+
|
59
|
+
buster.natural_key #=> "lou-gehrig-37693cf"
|
60
|
+
|
61
|
+
buster.name = 'The Iron Horse'
|
62
|
+
|
63
|
+
buster.natural_key #=> "the-iron-horse-37693cf"
|
64
|
+
|
65
|
+
`NaturalBornSlugger` interprets many objects as valid transformations:
|
66
|
+
|
67
|
+
##### Symbols:
|
68
|
+
- Converts dependency to string and sends the symbol tranformation to the `String` instance.
|
69
|
+
- `NaturalBornSlugger` extends `String` with two methods:
|
70
|
+
1. `hashify` - an alias for [ActiveSupports's parameterize method](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize)
|
71
|
+
2. `dashify` - convert string to an MD5 hash and use the first 7 digits
|
72
|
+
- Examples: `:hashify`, `:dashify`, `:capitalize`, `:chomp`, `:downcase`, `:reverse`, `:squeeze`, `:strip`, `:upcase`, etc
|
73
|
+
|
74
|
+
##### Strings:
|
75
|
+
- Attempts to use the string tranformation as a [format string](http://apidock.com/ruby/Kernel/sprintf) for the dependency.
|
76
|
+
- If the string tranformation isn't a format string, it will replace the dependency in the slug, which probably isn't what you want.
|
77
|
+
- Examples: `id: "%05d"`, `cost: "$%.02f"`
|
78
|
+
|
79
|
+
##### Regexps:
|
80
|
+
- Scans the dependency using the regex tranformation and joins all matches.
|
81
|
+
- Joins matches with the same `join_with` used in the rest of the slug.
|
82
|
+
- Examples: Can't think of any uses
|
83
|
+
|
84
|
+
##### Procs:
|
85
|
+
- Passes the dependency into the provided `lambda` or `Proc`.
|
86
|
+
- Allows custom tranformations. The `Proc` must accept one parameter and return a string or nil.
|
87
|
+
- Examples: compacting arrays of related objects, ie: `followers: ->(followers){ "%05d" % followers.count }`
|
88
|
+
|
89
|
+
##### nil, false, or anything else:
|
90
|
+
- Convert dependency to string and leave untouched.
|
91
|
+
- `nil` is preferred.
|
92
|
+
|
93
|
+
|
94
|
+
### Composed Attribute Options
|
95
|
+
|
96
|
+
After including `NaturalBornSlugger` into your class, you can define an composite attribute through one of three methods:
|
97
|
+
|
98
|
+
- `has_slug`
|
99
|
+
- `has_natural_key`
|
100
|
+
- `has_composed_attribute`
|
101
|
+
|
102
|
+
Each of these methods accepts the same arguments: a name and a hash of options. `has_slug` and `has_natural_key` will use default names of `'slug'` and `'natural_key'` respectively if you do not supply one. `has_composed_attribute` requires the name.
|
103
|
+
|
104
|
+
The options hash is where you define the attribute's dependencies. It also uses special keys to customize the attribute's behavior:
|
105
|
+
|
106
|
+
##### `:join_with`
|
107
|
+
- String to use for joining dependencies.
|
108
|
+
- Default: ""
|
109
|
+
- Example:
|
110
|
+
|
111
|
+
```
|
112
|
+
Person = Struct.new(:first_name, :middle_name, :last_name) do
|
113
|
+
include NaturalBornSlugger
|
114
|
+
has_slug first_name: nil, middle_name: nil, last_name: nil, join_with: '-'
|
115
|
+
end
|
116
|
+
|
117
|
+
bambino = Person.new('Babe', nil, 'Ruth')
|
118
|
+
bambino.slug #=> "Babe-Ruth"
|
119
|
+
```
|
120
|
+
|
121
|
+
##### `:compact`
|
122
|
+
- Removes nil dependencies before joining.
|
123
|
+
- Default: true
|
124
|
+
- Example: Notice the extra dash in the example below:
|
125
|
+
|
126
|
+
```
|
127
|
+
Person = Struct.new(:first_name, :middle_name, :last_name) do
|
128
|
+
include NaturalBornSlugger
|
129
|
+
has_slug first_name: nil, middle_name: nil, last_name: nil, compact: false, join_with: '-'
|
130
|
+
end
|
131
|
+
|
132
|
+
bambino = Person.new('Babe', nil, 'Ruth')
|
133
|
+
bambino.slug #=> "Babe--Ruth"
|
134
|
+
```
|
135
|
+
|
136
|
+
##### `:require_all`
|
137
|
+
- Checks to make sure all attributes exist before composing attribute.
|
138
|
+
- Makes attribute return nil until all dependencies exist.
|
139
|
+
- Default: false
|
140
|
+
- Example:
|
141
|
+
|
142
|
+
```
|
143
|
+
Person = Struct.new(:first_name, :middle_name, :last_name) do
|
144
|
+
include NaturalBornSlugger
|
145
|
+
has_slug first_name: nil, middle_name: nil, last_name: nil, require_all: true
|
146
|
+
end
|
147
|
+
|
148
|
+
bambino = Person.new('Babe', nil, 'Ruth')
|
149
|
+
bambino.slug #=> nil
|
150
|
+
|
151
|
+
bambino.first_name, bambino.middle_name = 'George', 'Herman'
|
152
|
+
bambino.slug #=> "George-Herman-Ruth"
|
153
|
+
```
|
154
|
+
|
155
|
+
##### `:track`
|
156
|
+
- Provides a callback function `#{attribute_name}_change` to allow you to persist old slugs as you please.
|
157
|
+
- Default: false
|
158
|
+
- Example:
|
159
|
+
|
160
|
+
```
|
161
|
+
Person = Struct.new(:first_name, :middle_name, :last_name) do
|
162
|
+
include NaturalBornSlugger
|
163
|
+
has_slug first_name: nil, middle_name: nil, last_name: nil, track: true
|
164
|
+
|
165
|
+
attr_accessor :formerly_known_as
|
166
|
+
def slug_change(old_slug, new_slug)
|
167
|
+
@formerly_known_as ||= []
|
168
|
+
@formerly_known_as << old_slug
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
bambino = Person.new('George', 'Herman', 'Ruth')
|
173
|
+
bambino.slug #=> "GeorgeHermanRuth"
|
174
|
+
|
175
|
+
bambino.first_name, bambino.middle_name = 'Babe', nil
|
176
|
+
bambino.slug #=> "BabeRuth"
|
177
|
+
bambino.formerly_known_as #=> ["GeorgeHermanRuth"]
|
178
|
+
```
|
179
|
+
|
180
|
+
##### _Note:_
|
181
|
+
|
182
|
+
If you happen to have methods or attributes called `join_with`, `compact`, `require_all`, or `track`, you can still build composite attributes out of them. Just use a string instead of a symbol when declaring your attribute's dependencies. `NaturalBornSlugger` only looks for symbols when reading your dependencies for these settings.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module NaturalBornSlugger
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
##
|
5
|
+
# Adds a slug to the class. Name is optional.
|
6
|
+
#
|
7
|
+
def has_slug(name, options={})
|
8
|
+
# Use default name if not provided
|
9
|
+
name, options = 'slug', name if name.is_a?(Hash)
|
10
|
+
dependencies, options = extract_composite_dependencies(name, options)
|
11
|
+
build_composite_attribute(name.to_s, dependencies, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Adds a natural key to the class. Name is optional.
|
16
|
+
#
|
17
|
+
def has_natural_key(name, options={})
|
18
|
+
# Use default name if not provided
|
19
|
+
name, options = 'natural_key', name if name.is_a?(Hash)
|
20
|
+
dependencies, options = extract_composite_dependencies(name, options)
|
21
|
+
build_composite_attribute(name.to_s, dependencies, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Adds a generic composite attribute to the class. Name is required.
|
26
|
+
#
|
27
|
+
def has_composite_attribute(name, options={})
|
28
|
+
dependencies, options = extract_composite_dependencies(name, options)
|
29
|
+
build_composite_attribute(name.to_s, dependencies, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
##
|
35
|
+
# Pulls method behavior options out of general options. The remaining options
|
36
|
+
# are assumed to be the dependent attributes that compose this one.
|
37
|
+
#
|
38
|
+
def extract_composite_dependencies(name, options={})
|
39
|
+
dependencies, options = options, {}
|
40
|
+
|
41
|
+
options[:compact_dependencies] = dependencies.delete(:compact) || true
|
42
|
+
options[:require_dependencies] = dependencies.delete(:require_all) || false
|
43
|
+
options[:track_changes] = dependencies.delete(:track) || false
|
44
|
+
options[:joiner] = dependencies.delete(:join_with) || ''
|
45
|
+
|
46
|
+
raise ConfigurationError.new(self.name, name, "no dependent attributes were specified") if dependencies.empty?
|
47
|
+
|
48
|
+
[dependencies, options]
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Adds a composite attribute to the class,
|
53
|
+
# with a getter and updater method.
|
54
|
+
# Also adds a setter that either calls the updater
|
55
|
+
# or throws an error, depending on configuration.
|
56
|
+
#
|
57
|
+
def build_composite_attribute(name, dependencies, options)
|
58
|
+
|
59
|
+
# Define instance attribute getter
|
60
|
+
define_method name do
|
61
|
+
self.send "update_#{name}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Define instance attribute setter: ignores assignment and just triggers an update
|
65
|
+
define_method "#{name}=" do |value|
|
66
|
+
if NaturalBornSlugger.configuration.ignore_attribute_setters
|
67
|
+
# TODO: Log discarded value warning
|
68
|
+
self.send "update_#{name}"
|
69
|
+
else
|
70
|
+
raise IllegalOperationError.new(self.class.name, "#{name}=", 'you cannot set composite attributes directly')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Update instance attribute
|
75
|
+
define_method "update_#{name}" do
|
76
|
+
# Check existence of all attribute dependencies if `require_dependencies` is true
|
77
|
+
resolved_dependencies = dependencies.map do |dependency, strategy|
|
78
|
+
[resolve_dependency(dependency), strategy]
|
79
|
+
end
|
80
|
+
if options[:require_dependencies] ? resolved_dependencies.map(&:first).all? : true
|
81
|
+
new_value = self.compose_attribute(resolved_dependencies, options)
|
82
|
+
if options[:track_changes]
|
83
|
+
old_value = self.instance_variable_get("@#{name}")
|
84
|
+
unless old_value == new_value
|
85
|
+
self.send("#{name}_change".to_sym, old_value, new_value)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
self.instance_variable_set("@#{name}", new_value)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
if [:track_changes]
|
93
|
+
define_method "#{name}_change" do |old_value, new_value|
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module NaturalBornSlugger
|
2
|
+
|
3
|
+
class NaturalBornError < StandardError; end
|
4
|
+
|
5
|
+
class IllegalOperationError < NaturalBornError
|
6
|
+
def initialize(class_name, method_name, context = nil)
|
7
|
+
@class_name = class_name
|
8
|
+
@method_name = method_name
|
9
|
+
@context = context
|
10
|
+
@message = "Cannot call `#{class_name}.#{method_name}"
|
11
|
+
end
|
12
|
+
def to_s
|
13
|
+
[@message, @context].compact.join(': ')+'.'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ConfigurationError < NaturalBornError
|
18
|
+
def initialize(class_name, attribute, context = nil)
|
19
|
+
@class_name = class_name
|
20
|
+
@attribute = attribute
|
21
|
+
@context = context
|
22
|
+
@message = "Composite attribute `#{attribute}` of #{class_name} has not been configured properly"
|
23
|
+
end
|
24
|
+
def to_s
|
25
|
+
[@message, @context].compact.join(': ')+'.'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module NaturalBornSlugger
|
2
|
+
|
3
|
+
def resolve_dependency(dependency)
|
4
|
+
object = self
|
5
|
+
dependency_chain = dependency.to_s.split('.')
|
6
|
+
dependency_chain.each do |method|
|
7
|
+
object = object.try :send, method
|
8
|
+
break unless object
|
9
|
+
end
|
10
|
+
object
|
11
|
+
end
|
12
|
+
|
13
|
+
def compose_attribute(resolved_dependencies, options)
|
14
|
+
resolved_dependencies.map do |resolved_dependency, strategy|
|
15
|
+
case strategy
|
16
|
+
when Symbol # Symbols represent string methods to call on the resolved dependency
|
17
|
+
resolved_dependency.to_s.send(strategy)
|
18
|
+
when String # Strings represent formats to fit the resolved dependency into
|
19
|
+
strategy % resolved_dependency
|
20
|
+
when Regexp # Regexps represent patterns to pull out of the resolved dependency and join
|
21
|
+
resolved_dependency.scan(strategy).join(options[:joiner])
|
22
|
+
when Proc # Procs should take one parameter and return a string or nil
|
23
|
+
strategy.call(resolved_dependency)
|
24
|
+
else # If no strategy provided, use resolved dependency as is
|
25
|
+
resolved_dependency.to_s
|
26
|
+
end
|
27
|
+
# Remove nil components if `compact_dependencies` is true
|
28
|
+
end.tap do |components|
|
29
|
+
components.compact! if options[:compact_dependencies]
|
30
|
+
end.join(options[:joiner])
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
+
|
3
|
+
require "natural_born_slugger/exceptions"
|
4
|
+
require "natural_born_slugger/configuration"
|
5
|
+
|
6
|
+
module NaturalBornSlugger
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.configure
|
13
|
+
self.configuration ||= Configuration.new
|
14
|
+
|
15
|
+
yield(configuration) if block_given?
|
16
|
+
|
17
|
+
require "natural_born_slugger/class_methods"
|
18
|
+
require "natural_born_slugger/instance_methods"
|
19
|
+
|
20
|
+
configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.logger
|
24
|
+
@logger ||= configuration.logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.included(base)
|
28
|
+
base.extend ClassMethods
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
require "natural_born_slugger/extensions/string"
|
33
|
+
require "natural_born_slugger/version"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'natural_born_slugger/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "natural_born_slugger"
|
8
|
+
spec.version = NaturalBornSlugger::VERSION
|
9
|
+
spec.authors = ["Christopher Keele"]
|
10
|
+
spec.email = ["dev@chriskeele.com"]
|
11
|
+
spec.description = %q{A gem for managing composed attributes, especially natural keys and url slugs.}
|
12
|
+
spec.summary = %q{Easily define automatically-updated composed attributes. Includes ORM helpers and a Rack-based URL redirector.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
24
|
+
spec.add_development_dependency "redcarpet", "~> 2.2"
|
25
|
+
spec.add_development_dependency "rspec", "~> 2.13"
|
26
|
+
|
27
|
+
spec.add_dependency 'activesupport', '~> 3.1'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: natural_born_slugger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Keele
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: redcarpet
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.13'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.13'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.1'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.1'
|
97
|
+
description: A gem for managing composed attributes, especially natural keys and url
|
98
|
+
slugs.
|
99
|
+
email:
|
100
|
+
- dev@chriskeele.com
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- .yardopts
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.md
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- lib/natural_born_slugger.rb
|
112
|
+
- lib/natural_born_slugger/class_methods.rb
|
113
|
+
- lib/natural_born_slugger/configuration.rb
|
114
|
+
- lib/natural_born_slugger/exceptions.rb
|
115
|
+
- lib/natural_born_slugger/extensions/string.rb
|
116
|
+
- lib/natural_born_slugger/instance_methods.rb
|
117
|
+
- lib/natural_born_slugger/version.rb
|
118
|
+
- natural_born_slugger.gemspec
|
119
|
+
homepage: ''
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata: {}
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 2.0.0
|
140
|
+
signing_key:
|
141
|
+
specification_version: 4
|
142
|
+
summary: Easily define automatically-updated composed attributes. Includes ORM helpers
|
143
|
+
and a Rack-based URL redirector.
|
144
|
+
test_files: []
|
145
|
+
has_rdoc:
|