rep 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +168 -0
- data/Rakefile +8 -0
- data/lib/rep/version.rb +3 -0
- data/lib/rep.rb +150 -0
- data/rep.gemspec +20 -0
- data/test/lib/rep_test.rb +142 -0
- data/test/test_helper.rb +9 -0
- metadata +74 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 myobie
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
# Rep
|
2
|
+
|
3
|
+
```
|
4
|
+
/T /I
|
5
|
+
/ |/ | .-~/
|
6
|
+
T\ Y I |/ / _
|
7
|
+
/T | \I | I Y.-~/
|
8
|
+
I l /I T\ | | l | T /
|
9
|
+
__ | \l \l \I l __l l \ ` _. |
|
10
|
+
\ ~-l `\ `\ \ \\ ~\ \ `. .-~ |
|
11
|
+
\ ~-. "-. ` \ ^._ ^. "-. / \ |
|
12
|
+
.--~-._ ~- ` _ ~-_.-"-." ._ /._ ." ./
|
13
|
+
>--. ~-. ._ ~>-" "\\ 7 7 ]
|
14
|
+
^.___~"--._ ~-{ .-~ . `\ Y . / |
|
15
|
+
<__ ~"-. ~ /_/ \ \I Y : |
|
16
|
+
^-.__ ~(_/ \ >._: | l______
|
17
|
+
^--.,___.-~" /_/ ! `-.~"--l_ / ~"-.
|
18
|
+
(_/ . ~( /' "~"--,Y -=b-. _)
|
19
|
+
(_/ . \ : / l c"~o \
|
20
|
+
\ / `. . .^ \_.-~"~--. )
|
21
|
+
(_/ . ` / / ! )/
|
22
|
+
/ / _. '. .': / '
|
23
|
+
~(_/ . / _ ` .-<_
|
24
|
+
/_/ . ' .-~" `. / \ \ ,z=.
|
25
|
+
~( / ' : | K "-.~-.______//
|
26
|
+
"-,. l I/ \_ __{--->._(==.
|
27
|
+
//( \ < ~"~" //
|
28
|
+
/' /\ \ \ ,v=. ((
|
29
|
+
.^. / /\ " }__ //===- `
|
30
|
+
/ / ' ' "-.,__ {---(==-
|
31
|
+
.^ ' : T ~" ll
|
32
|
+
/ . . . : | :! \\
|
33
|
+
(_/ / | | j-" ~^
|
34
|
+
~-<_(_.^-~"
|
35
|
+
```
|
36
|
+
|
37
|
+
A library for writing authoritative representations of objects for pages and apis.
|
38
|
+
|
39
|
+
## Installation
|
40
|
+
|
41
|
+
Add this line to your application's Gemfile:
|
42
|
+
|
43
|
+
gem 'rep'
|
44
|
+
|
45
|
+
And then execute:
|
46
|
+
|
47
|
+
$ bundle
|
48
|
+
|
49
|
+
Or install it yourself as:
|
50
|
+
|
51
|
+
$ gem install rep
|
52
|
+
|
53
|
+
## Usage
|
54
|
+
|
55
|
+
`include Rep` into any class and it is endowed with a `#to_json` method,
|
56
|
+
among other things. You describe the top level keys you want for your
|
57
|
+
json with the `::fields` method. The values for the fields are expected
|
58
|
+
to be returned from methods on the object of the same name.
|
59
|
+
|
60
|
+
If a class has `fields :one => :default`, then `def one; 1; end` is
|
61
|
+
expected.
|
62
|
+
|
63
|
+
## Examples
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# imagine Photo is an ActiveRecord model with fields for title, exif, location, and user_id
|
67
|
+
|
68
|
+
class PhotoRep
|
69
|
+
include Rep
|
70
|
+
|
71
|
+
initialize_with :photo
|
72
|
+
|
73
|
+
json_fields [:url, :title, :exif, :location, :user] => :default
|
74
|
+
|
75
|
+
forward [:title, :exif, :location] => :photo
|
76
|
+
forward :user => :user_rep
|
77
|
+
|
78
|
+
def url
|
79
|
+
full_photo_url(photo.name)
|
80
|
+
end
|
81
|
+
|
82
|
+
def user
|
83
|
+
UserRep.shared(user: photo.user)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# imagine User is an ActiveRecord model with fields for name, email, and location
|
88
|
+
|
89
|
+
class UserRep
|
90
|
+
include Rep
|
91
|
+
|
92
|
+
initialize_with :user
|
93
|
+
|
94
|
+
json_fields [:name, :email, :location] => :default
|
95
|
+
json_fields [:id, :admin].concat(json_fields(:default)) => :admin
|
96
|
+
|
97
|
+
forward json_fields(:admin) => :user
|
98
|
+
end
|
99
|
+
|
100
|
+
# You can now do crazy stuff like
|
101
|
+
|
102
|
+
UserRep.new(user: User.first).to_hash.keys # => [:name, :email, :location]
|
103
|
+
|
104
|
+
# To save from creating lots of objects, you can use a shared class that is reset fresh
|
105
|
+
UserRep.shared(user: User.first).to_hash # => { name: "Nathan Herald:, ...
|
106
|
+
|
107
|
+
# You can use class to proc (that makes a hash using the shared class)
|
108
|
+
User.all.map(&UserRep) # => [{ name: "Nathan Herald" ...
|
109
|
+
|
110
|
+
# or maybe find all photos which will embed all users (and only ever make one instance each of PhotoRep and UserRep)
|
111
|
+
Photo.all.map(&PhotoRep).to_json
|
112
|
+
```
|
113
|
+
|
114
|
+
### Any class
|
115
|
+
|
116
|
+
You don't have to have a Rep per model and Rep's can represent multiple objects at once. It's POROs.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
class ProjectReport
|
120
|
+
initialize_with :project, :active_users, :orders
|
121
|
+
fields [:name, :date, :count, :total_gross_cost, :cost_per_active_user]
|
122
|
+
forward :date => :project
|
123
|
+
forward :count => :orders
|
124
|
+
|
125
|
+
def name
|
126
|
+
"#{project.name} Report"
|
127
|
+
end
|
128
|
+
|
129
|
+
def total_gross_cost
|
130
|
+
orders.reduce(0.0) { |memo, order| memo += order.total_gross_cost.to_f }
|
131
|
+
end
|
132
|
+
|
133
|
+
def cost_per_active_user
|
134
|
+
active_users.count.to_f / total_gross_cost.to_f
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
### Hashie
|
140
|
+
|
141
|
+
If you have the hashie gem in your project, `#to_hash` returns a `Hashie::Mash` instance.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
UserRep.new(user: User.first).to_hash.class # => Hashie::Mash
|
145
|
+
|
146
|
+
# which lets you do the dot accessors for things
|
147
|
+
@user = UserRep.new(user: User.first).to_hash
|
148
|
+
@user.name # => "Nathan Herald"
|
149
|
+
```
|
150
|
+
|
151
|
+
### Rails
|
152
|
+
|
153
|
+
A possible controller
|
154
|
+
```ruby
|
155
|
+
class PhotosController < ApplicationController
|
156
|
+
respond_to :json, :html
|
157
|
+
|
158
|
+
def index
|
159
|
+
@photos = Photo.paginate(page: params[:page], per_page: 20)
|
160
|
+
respond_with @photos.map(&PhotoRep)
|
161
|
+
end
|
162
|
+
|
163
|
+
def show
|
164
|
+
@photo = Photo.find(params[:id])
|
165
|
+
respond_with PhotoRep.new(photo: @photo)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
data/Rakefile
ADDED
data/lib/rep/version.rb
ADDED
data/lib/rep.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require "rep/version"
|
2
|
+
require 'forwardable'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Rep
|
6
|
+
def self.included(klass)
|
7
|
+
klass.extend Forwardable
|
8
|
+
klass.extend ClassMethods
|
9
|
+
klass.instance_eval {
|
10
|
+
class << self
|
11
|
+
alias forward delegate
|
12
|
+
|
13
|
+
unless defined?(fields)
|
14
|
+
alias fields json_fields
|
15
|
+
end
|
16
|
+
|
17
|
+
if defined?(Hashie)
|
18
|
+
include HashieSupport
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
unless defined?(parse_opts)
|
23
|
+
def parse_opts(opts = {})
|
24
|
+
# NOOP
|
25
|
+
end
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset_for_json!
|
31
|
+
self.class.all_json_methods.each do |method_name|
|
32
|
+
instance_variable_set(:"@#{method_name}", nil)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash(name = :default)
|
37
|
+
if fields = self.class.json_fields(name)
|
38
|
+
fields.reduce({}) do |memo, field|
|
39
|
+
field_name, method_name = field.is_a?(Hash) ? field.to_a.first : [field, field]
|
40
|
+
begin
|
41
|
+
memo[field_name] = send(method_name)
|
42
|
+
rescue NoMethodError => e
|
43
|
+
message = "There is no method named '#{method_name}' for the class '#{self.class}' for the '#{name}' list of fields : #{e.message}"
|
44
|
+
raise NoMethodError.new(message, method_name, e.args)
|
45
|
+
end
|
46
|
+
memo
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise "There are no json fields under the name: #{name}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_json
|
54
|
+
JSON.generate(to_hash)
|
55
|
+
end
|
56
|
+
|
57
|
+
module ClassMethods
|
58
|
+
def register_accessor(acc)
|
59
|
+
name, default = acc.is_a?(Hash) ? acc.to_a.first : [acc, nil]
|
60
|
+
attr_accessor name
|
61
|
+
if default
|
62
|
+
define_method name do
|
63
|
+
var_name = :"@#{name}"
|
64
|
+
instance_variable_get(var_name) || instance_variable_set(var_name, default)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize_with(*args)
|
70
|
+
@initializiation_args = args
|
71
|
+
|
72
|
+
define_singleton_method :initializiation_args do
|
73
|
+
@initializiation_args
|
74
|
+
end
|
75
|
+
|
76
|
+
args.each { |a| register_accessor(a) }
|
77
|
+
|
78
|
+
define_method(:initialize) { |opts = {}| parse_opts(opts) }
|
79
|
+
|
80
|
+
define_method :parse_opts do |opts|
|
81
|
+
@presidential_options = opts
|
82
|
+
self.class.initializiation_args.each do |field|
|
83
|
+
name = field.is_a?(Hash) ? field.to_a.first.first : field
|
84
|
+
instance_variable_set(:"@#{name}", opts[name])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def json_fields(arg = nil)
|
90
|
+
if arg.is_a?(Hash)
|
91
|
+
fields, name = arg.to_a.first
|
92
|
+
@json_fields ||= {}
|
93
|
+
@json_fields[name] = [fields].flatten
|
94
|
+
elsif arg.is_a?(Symbol)
|
95
|
+
@json_fields ||= {}
|
96
|
+
@json_fields[arg]
|
97
|
+
elsif arg === nil
|
98
|
+
@json_fields || {}
|
99
|
+
else
|
100
|
+
# TODO: make an exception class
|
101
|
+
raise "You can only use a Hash to set fields, a Symbol to retrieve them, or no argument to retrieve all fields for all names"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def flat_json_fields(side = :right)
|
106
|
+
side_number = side == :right ? 1 : 0
|
107
|
+
|
108
|
+
json_fields.reduce([]) do |memo, (name, fields)|
|
109
|
+
memo + fields.map do |field|
|
110
|
+
if field.is_a?(Hash)
|
111
|
+
field.to_a.first[side_number] # [name, method_name]
|
112
|
+
else
|
113
|
+
field
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end.uniq
|
117
|
+
end
|
118
|
+
|
119
|
+
def all_json_fields
|
120
|
+
flat_json_fields(:left)
|
121
|
+
end
|
122
|
+
|
123
|
+
def all_json_methods
|
124
|
+
flat_json_fields(:right)
|
125
|
+
end
|
126
|
+
|
127
|
+
# TODO: thread safety
|
128
|
+
def shared(opts = {})
|
129
|
+
@instance ||= new
|
130
|
+
@instance.reset_for_json!
|
131
|
+
@instance.parse_opts(opts)
|
132
|
+
@instance
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_proc
|
136
|
+
proc { |obj|
|
137
|
+
arr = [obj].flatten
|
138
|
+
init_args = @initializiation_args[0..(arr.length-1)]
|
139
|
+
opts = Hash[init_args.zip(arr)]
|
140
|
+
shared(opts).to_hash
|
141
|
+
}
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module HashieSupport
|
146
|
+
def to_hash(name = :default)
|
147
|
+
Hashie::Mash.new(super)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/rep.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rep/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "rep"
|
8
|
+
gem.version = Rep::VERSION
|
9
|
+
gem.authors = ["myobie"]
|
10
|
+
gem.email = ["nathan@myobie.com"]
|
11
|
+
gem.description = %q{A library for writing authoritative representations of objects for pages and apis.}
|
12
|
+
gem.summary = %q{Include Rep into any object to endow it to create json (or hashes) easily.}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.add_dependency 'json'
|
20
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Rep do
|
4
|
+
|
5
|
+
def new_rep_class(&blk)
|
6
|
+
klass = Class.new
|
7
|
+
klass.send :include, Rep
|
8
|
+
if block_given?
|
9
|
+
klass.class_eval &blk
|
10
|
+
end
|
11
|
+
klass
|
12
|
+
end
|
13
|
+
|
14
|
+
it "includes forwardable" do
|
15
|
+
new_rep_class.must_respond_to :delegate
|
16
|
+
end
|
17
|
+
|
18
|
+
it "aliases delegate to foward" do
|
19
|
+
new_rep_class.must_respond_to :forward
|
20
|
+
end
|
21
|
+
|
22
|
+
it "aliases fields to json_fields" do
|
23
|
+
new_rep_class.must_respond_to :fields
|
24
|
+
end
|
25
|
+
|
26
|
+
it "has a parse_opts method" do
|
27
|
+
new_rep_class.must_respond_to :parse_opts
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can have fields" do
|
31
|
+
klass = new_rep_class do
|
32
|
+
fields [:foo, :bar] => :default
|
33
|
+
end
|
34
|
+
klass.fields(:default).must_equal [:foo, :bar]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can create initialize method" do
|
38
|
+
klass = new_rep_class do
|
39
|
+
initialize_with :foo, :bar
|
40
|
+
end
|
41
|
+
inst = klass.new(foo: 'foo123')
|
42
|
+
inst.foo.must_equal 'foo123'
|
43
|
+
inst.bar.must_be_nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can have default initialization options" do
|
47
|
+
klass = new_rep_class do
|
48
|
+
initialize_with :foo, { bar: "barbar" }
|
49
|
+
end
|
50
|
+
inst = klass.new(foo: 'foofoo')
|
51
|
+
inst.bar.must_equal 'barbar'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "can overried default initialization options" do
|
55
|
+
klass = new_rep_class do
|
56
|
+
initialize_with :foo, { bar: "barbar" }
|
57
|
+
end
|
58
|
+
inst = klass.new(bar: 'notbar')
|
59
|
+
inst.bar.must_equal 'notbar'
|
60
|
+
inst.foo.must_be_nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should accept multiple sets of fields" do
|
64
|
+
klass = new_rep_class do
|
65
|
+
fields [:one, :four] => :default
|
66
|
+
fields [:one, :two, :three] => :superset
|
67
|
+
end
|
68
|
+
klass.fields(:default).length.must_equal 2
|
69
|
+
klass.fields(:superset).length.must_equal 3
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should know all uniq fields" do
|
73
|
+
klass = new_rep_class do
|
74
|
+
fields [:one, :four] => :default
|
75
|
+
fields [:one, :two, :three] => :superset
|
76
|
+
end
|
77
|
+
klass.all_json_fields.must_equal [:one, :four, :two, :three]
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should send fields to instance to make hash" do
|
81
|
+
klass = new_rep_class do
|
82
|
+
fields [:one, :two, :three] => :default
|
83
|
+
def one; 1; end
|
84
|
+
def two; 2; end
|
85
|
+
def three; 3; end
|
86
|
+
end
|
87
|
+
klass.new.to_hash.must_equal one: 1, two: 2, three: 3
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should send fields to instance to make json" do
|
91
|
+
klass = new_rep_class do
|
92
|
+
fields [:one, :two, :three] => :default
|
93
|
+
def one; 1; end
|
94
|
+
def two; 2; end
|
95
|
+
def three; 3; end
|
96
|
+
end
|
97
|
+
klass.new.to_json.must_equal '{"one":1,"two":2,"three":3}'
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should let fields alias to method names" do
|
101
|
+
klass = new_rep_class do
|
102
|
+
fields [{ :one => :real_one }, :two, :three] => :default
|
103
|
+
def real_one; 1; end
|
104
|
+
def two; 2; end
|
105
|
+
def three; 3; end
|
106
|
+
end
|
107
|
+
klass.new.to_json.must_equal '{"one":1,"two":2,"three":3}'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should know all the methods for the fields" do
|
111
|
+
klass = new_rep_class do
|
112
|
+
fields [{ :one => :real_one }, :two, :three] => :default
|
113
|
+
def real_one; 1; end
|
114
|
+
def two; 2; end
|
115
|
+
def three; 3; end
|
116
|
+
end
|
117
|
+
klass.all_json_methods.must_equal [:real_one, :two, :three]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should know all the field names for the fields" do
|
121
|
+
klass = new_rep_class do
|
122
|
+
fields [{ :one => :real_one }, :two, :three] => :default
|
123
|
+
def real_one; 1; end
|
124
|
+
def two; 2; end
|
125
|
+
def three; 3; end
|
126
|
+
end
|
127
|
+
klass.all_json_fields.must_equal [:one, :two, :three]
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should do symbol to instance craziness" do
|
131
|
+
klass = new_rep_class do
|
132
|
+
initialize_with :hash
|
133
|
+
fields :keys => :default
|
134
|
+
forward :keys => :hash
|
135
|
+
end
|
136
|
+
hashes = [{ one: 1, two: 2 },
|
137
|
+
{ three: 3, four: 4 },
|
138
|
+
{ one: 1, five: 5 }]
|
139
|
+
hashes.map(&klass).to_json.must_equal '[{"keys":["one","two"]},{"keys":["three","four"]},{"keys":["one","five"]}]'
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rep
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- myobie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A library for writing authoritative representations of objects for pages
|
31
|
+
and apis.
|
32
|
+
email:
|
33
|
+
- nathan@myobie.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- lib/rep.rb
|
44
|
+
- lib/rep/version.rb
|
45
|
+
- rep.gemspec
|
46
|
+
- test/lib/rep_test.rb
|
47
|
+
- test/test_helper.rb
|
48
|
+
homepage: ''
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.23
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Include Rep into any object to endow it to create json (or hashes) easily.
|
72
|
+
test_files:
|
73
|
+
- test/lib/rep_test.rb
|
74
|
+
- test/test_helper.rb
|