hokusai 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +147 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/hokusai.gemspec +31 -0
- data/lib/hokusai.rb +122 -0
- data/lib/hokusai/version.rb +3 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f863b83808f9657284136b67742c7603d6fbfef2
|
4
|
+
data.tar.gz: 678e6a74b4bfea5cd8cbdc3bf56ec16e4d5827f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 148209dba74cb5298424a8ca3023b982c5fda80915b33e151859615ae83f4641d7bf441ca6bc3a5529b8018faf17fcff4416db90e0ca4a75f616e79f2a80509e
|
7
|
+
data.tar.gz: ce93b31386807f7ec79213ee79733bcbc0392ba4004162123afe6757f21e30620300b86f4cc0f677f08776aff3bca09005d23550deafefebe8c7af00c58aca96
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Josh Goodall
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# Hokusai
|
2
|
+
|
3
|
+
Stamp out domain-specific clones of a model object, even after the original has departed, with these lightweight ActiveRecord concerns.
|
4
|
+
|
5
|
+
## Quick demo
|
6
|
+
|
7
|
+
If you want to write code like this, snapshotting an ActiveRecord object (and perhaps some associations) into a template:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
@template = Template.create!(origin: @project, name: "New template from project")
|
11
|
+
```
|
12
|
+
|
13
|
+
hoping to use it like this, at some later time (perhaps long after the origin has been deleted):
|
14
|
+
|
15
|
+
```
|
16
|
+
template = Template.find(params[:template_id])
|
17
|
+
@new_project = template.stamp do |project|
|
18
|
+
project.name = "New project from template"
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
then you have (maybe) come to the right place.
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem 'hokusai'
|
30
|
+
```
|
31
|
+
|
32
|
+
And then execute:
|
33
|
+
|
34
|
+
$ bundle
|
35
|
+
|
36
|
+
Or install it yourself as:
|
37
|
+
|
38
|
+
$ gem install hokusai
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
Include `Hokusai::Container` in an ActiveRecord model so that we can save templates in it. The columns `hokusai_class` and `hokusai_template` are required. You can add whatever data or metadata you wish, from a simple name to complex lifecycle or ownership attributes. In this example we just require a name:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class Template < ApplicationRecord
|
46
|
+
include Hokusai::Container
|
47
|
+
validates :name, presence: true
|
48
|
+
before_validation :ensure_name
|
49
|
+
|
50
|
+
private
|
51
|
+
def ensure_name
|
52
|
+
self.name = "New #{hokusai_class.constantize.model_name.singular} template"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
Now create and run a suitable migration:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class CreateTemplates < ActiveRecord::Migration
|
61
|
+
def change
|
62
|
+
create_table :templates do |t|
|
63
|
+
t.string :name, null: false
|
64
|
+
t.string :hokusai_class, null: false
|
65
|
+
t.text :hokusai_template, null: false
|
66
|
+
t.timestamps
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
Then include `Hokusai::Templatable` in the models you want to make templates from. Declare a list of columns to persist, and which associations to include:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class Device < ApplicationRecord
|
76
|
+
include Hokusai::Templatable
|
77
|
+
|
78
|
+
template :name, :model, :location, :year, include: [:interfaces]
|
79
|
+
has_many :interfaces
|
80
|
+
end
|
81
|
+
|
82
|
+
class Interface < ApplicationRecord
|
83
|
+
include Hokusai::Templatable
|
84
|
+
belongs_to :device
|
85
|
+
|
86
|
+
template :name, :address, :enabled
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
You can then create a new template, and stamp out a copy:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
device = Device.create!(name: "router-1", model: "CX-6790", location: "SFO", year: 2017)
|
94
|
+
device.interfaces.create!([
|
95
|
+
{name: "de0", address: "10.0.0.1", enabled: false},
|
96
|
+
{name: "lo0", address: "127.0.0.1", enabled: true}
|
97
|
+
])
|
98
|
+
|
99
|
+
template = Template.create!(origin: device, name: 'SFO router template')
|
100
|
+
|
101
|
+
new_device = template.stamp do |device|
|
102
|
+
device.name = "router-2"
|
103
|
+
end
|
104
|
+
|
105
|
+
new_device.save!
|
106
|
+
```
|
107
|
+
|
108
|
+
This example ends with a deep, domain-specific clone of the origin object. You can delete the origin and the template is still useful.
|
109
|
+
|
110
|
+
### What can Hokusai stamp out?
|
111
|
+
|
112
|
+
Broadly speaking, this is intended for any ActiveRecord object that can be serialized to & from YAML.
|
113
|
+
|
114
|
+
The `Hokusai::Templatable` concern is provided. This handles ordinary `has_many`, `has_one`, and `belongs_to` associations via the `include:` option, in which case it will call `as_template` on the associated records. If you want a `belongs_to` reference id to carry across, serialize the _id column rather than including the association in the template.
|
115
|
+
|
116
|
+
Recursive serialization is not currently detected and will cause a "stack level too deep" error. For those you may need to implement `as_template` by hand.
|
117
|
+
|
118
|
+
Aggregates types may also need special treatment. You can override `read_attribute_for_template` in the model for these.
|
119
|
+
|
120
|
+
### Advanced configuration
|
121
|
+
|
122
|
+
You're not constrained to using `Hokusai::Templatable`. Any model that implements `#as_template` and `::from_template` will do, and the container doesn't impose constraints on their behaviour. The only expectation is that `#as_template` returns a data structure ready for serialization as YAML, and that `::from_template` accepts the same structure as the first parameter. Beyond that you can do as you please with the data.
|
123
|
+
|
124
|
+
## Todo
|
125
|
+
|
126
|
+
* Generator for the container migration.
|
127
|
+
* Support for serializing self-referential data structures.
|
128
|
+
* Clearer tests.
|
129
|
+
* Comprehensive tests for a wide range of complicated associations.
|
130
|
+
* Remove dependency on ActiveRecord.
|
131
|
+
* Support configurable column names and template assignment method name.
|
132
|
+
|
133
|
+
## Development
|
134
|
+
|
135
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
136
|
+
|
137
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
138
|
+
|
139
|
+
## Contributing
|
140
|
+
|
141
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/inopinatus/hokusai.
|
142
|
+
|
143
|
+
|
144
|
+
## License
|
145
|
+
|
146
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
147
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "hokusai"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/hokusai.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hokusai/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "hokusai"
|
8
|
+
spec.version = Hokusai::VERSION
|
9
|
+
spec.authors = ["Josh Goodall"]
|
10
|
+
spec.email = ["inopinatus@inopinatus.org"]
|
11
|
+
|
12
|
+
spec.summary = %q{Stamp out your models.}
|
13
|
+
spec.description = %q{Stamp out copies of a model object, even after the original has departed, with these lightweight ActiveRecord concerns.}
|
14
|
+
spec.homepage = "https://github.com/inopinatus/hokusai"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
27
|
+
spec.add_development_dependency "activerecord", "> 5.0"
|
28
|
+
spec.add_development_dependency "sqlite3"
|
29
|
+
spec.add_development_dependency "pry"
|
30
|
+
spec.add_dependency "activesupport", "> 5.0"
|
31
|
+
end
|
data/lib/hokusai.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require "hokusai/version"
|
2
|
+
require "active_support"
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module Hokusai
|
6
|
+
|
7
|
+
##
|
8
|
+
# Templatable models support taking a snapshot of their data, for later use stamping out clones.
|
9
|
+
#
|
10
|
+
# Include this module to obtain the +as_template+ and +from_template+ methods that support a simple container
|
11
|
+
# such as Hokusai::Container.
|
12
|
+
#
|
13
|
+
# Configure it with the +template+ declaration, which accepts a list of columns and an +includes+ option
|
14
|
+
# for nested assocations.
|
15
|
+
#
|
16
|
+
# === Example
|
17
|
+
#
|
18
|
+
# class Device < ActiveRecord::Base
|
19
|
+
# include Hokusai::Templatable
|
20
|
+
#
|
21
|
+
# has_many :interfaces
|
22
|
+
#
|
23
|
+
# template :name, :model, :location, :year, include: [:interfaces]
|
24
|
+
# end
|
25
|
+
|
26
|
+
module Templatable
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
included do
|
30
|
+
class_attribute :🌊
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
# Define the template specification for the model.
|
35
|
+
def template(*template_columns, **options)
|
36
|
+
template_columns = Array(template_columns).map(&:to_s)
|
37
|
+
included_associations = Array(options[:include]).map(&:to_s)
|
38
|
+
|
39
|
+
self.🌊 = {
|
40
|
+
columns: template_columns,
|
41
|
+
associations: included_associations,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Build a new, unsaved instance of the model (and any included associations) from the template supplied.
|
47
|
+
# The block will be called with the new instance.
|
48
|
+
def from_template(template, &block)
|
49
|
+
if template.is_a?(Array)
|
50
|
+
template.map { |tpl| from_template(tpl, &block) }
|
51
|
+
else
|
52
|
+
new_attrs = template.slice(*🌊[:columns])
|
53
|
+
template.slice(*🌊[:associations]).each do |association, association_template|
|
54
|
+
new_attrs[association] = reflect_on_association(association).klass.from_template(association_template)
|
55
|
+
end
|
56
|
+
new(new_attrs, &block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Serialize this object (and any included associations) according to the template specification.
|
63
|
+
def as_template
|
64
|
+
result_hash = {}
|
65
|
+
|
66
|
+
🌊[:columns].each_with_object(result_hash) do |column|
|
67
|
+
result_hash[column] = read_attribute_for_template(column)
|
68
|
+
end
|
69
|
+
|
70
|
+
🌊[:associations].each do |association|
|
71
|
+
records = send(association)
|
72
|
+
result_hash[association] = if records.respond_to?(:to_ary)
|
73
|
+
records.to_ary.map { |r| r.as_template }
|
74
|
+
else
|
75
|
+
records.as_template
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
result_hash
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
alias :read_attribute_for_template :send
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# This module supplies a simple container for snapshots of template-style data.
|
88
|
+
# These templates are used when stamping out new objects.
|
89
|
+
#
|
90
|
+
# A Hokusai container communicates with models via the +as_template+ method and +from_template+ class method.
|
91
|
+
# The data will be serialized as YAML; this container class is otherwise not concerned with its structure.
|
92
|
+
#
|
93
|
+
# Relies on the presence of two columns: +hokusai_class+ (string) and +hokusai_template+ (text).
|
94
|
+
|
95
|
+
module Container
|
96
|
+
extend ActiveSupport::Concern
|
97
|
+
|
98
|
+
included do
|
99
|
+
validates :hokusai_class, :hokusai_template, presence: true
|
100
|
+
end
|
101
|
+
|
102
|
+
# Set current template data, calling +as_template+ on the origin.
|
103
|
+
#
|
104
|
+
# Intended for use via <tt>@template = Template.new(origin: project, ...attrs...)</tt>
|
105
|
+
#
|
106
|
+
def origin=(object)
|
107
|
+
self.hokusai_class = object.class.to_s
|
108
|
+
self.hokusai_template = YAML.dump(object.as_template)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Stamp out a new object from the template. Calls +from_template+ on the applicable class with
|
112
|
+
# the deserialized template data, passing on any supplied block.
|
113
|
+
#
|
114
|
+
# The semantics of +from_template+ are left to the receiving model. If using the supplied
|
115
|
+
# concern <tt>Hokusai::Templatable</tt> then a new, unsaved model object will be instantiated,
|
116
|
+
# with nested models included as specified.
|
117
|
+
#
|
118
|
+
def stamp(&block)
|
119
|
+
hokusai_class.constantize.from_template(YAML.load(hokusai_template), &block)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hokusai
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Goodall
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-24 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.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
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: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activerecord
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activesupport
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '5.0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '5.0'
|
111
|
+
description: Stamp out copies of a model object, even after the original has departed,
|
112
|
+
with these lightweight ActiveRecord concerns.
|
113
|
+
email:
|
114
|
+
- inopinatus@inopinatus.org
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".gitignore"
|
120
|
+
- ".travis.yml"
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- bin/console
|
126
|
+
- bin/setup
|
127
|
+
- hokusai.gemspec
|
128
|
+
- lib/hokusai.rb
|
129
|
+
- lib/hokusai/version.rb
|
130
|
+
homepage: https://github.com/inopinatus/hokusai
|
131
|
+
licenses:
|
132
|
+
- MIT
|
133
|
+
metadata: {}
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 2.6.11
|
151
|
+
signing_key:
|
152
|
+
specification_version: 4
|
153
|
+
summary: Stamp out your models.
|
154
|
+
test_files: []
|