factory_burgers 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/assets/asset-manifest.json +23 -0
- data/lib/assets/bootstrap.4.0.0.min.css +6 -0
- data/lib/assets/favicon.ico +0 -0
- data/lib/assets/fonts/SpecialElite-Regular.ttf +0 -0
- data/lib/assets/index.html +1 -0
- data/lib/assets/layout.css +46 -0
- data/lib/assets/logo192.png +0 -0
- data/lib/assets/logo512.png +0 -0
- data/lib/assets/manifest.json +25 -0
- data/lib/assets/robots.txt +3 -0
- data/lib/assets/static/css/main.510d0fb6.chunk.css +2 -0
- data/lib/assets/static/css/main.510d0fb6.chunk.css.map +1 -0
- data/lib/assets/static/css/main.8c8b27cf.chunk.css +2 -0
- data/lib/assets/static/css/main.8c8b27cf.chunk.css.map +1 -0
- data/lib/assets/static/css/main.9d5b29c0.chunk.css +2 -0
- data/lib/assets/static/css/main.9d5b29c0.chunk.css.map +1 -0
- data/lib/assets/static/css/main.ff283a2d.chunk.css +2 -0
- data/lib/assets/static/css/main.ff283a2d.chunk.css.map +1 -0
- data/lib/assets/static/js/2.05989fca.chunk.js +3 -0
- data/lib/assets/static/js/2.05989fca.chunk.js.LICENSE.txt +47 -0
- data/lib/assets/static/js/2.05989fca.chunk.js.map +1 -0
- data/lib/assets/static/js/2.3cffa5b0.chunk.js +3 -0
- data/lib/assets/static/js/2.3cffa5b0.chunk.js.LICENSE.txt +41 -0
- data/lib/assets/static/js/2.3cffa5b0.chunk.js.map +1 -0
- data/lib/assets/static/js/2.3ff1dc5f.chunk.js +3 -0
- data/lib/assets/static/js/2.3ff1dc5f.chunk.js.LICENSE.txt +47 -0
- data/lib/assets/static/js/2.3ff1dc5f.chunk.js.map +1 -0
- data/lib/assets/static/js/2.42c06104.chunk.js +3 -0
- data/lib/assets/static/js/2.42c06104.chunk.js.LICENSE.txt +41 -0
- data/lib/assets/static/js/2.42c06104.chunk.js.map +1 -0
- data/lib/assets/static/js/2.72048743.chunk.js +3 -0
- data/lib/assets/static/js/2.72048743.chunk.js.LICENSE.txt +41 -0
- data/lib/assets/static/js/2.72048743.chunk.js.map +1 -0
- data/lib/assets/static/js/2.99b8c933.chunk.js +3 -0
- data/lib/assets/static/js/2.99b8c933.chunk.js.LICENSE.txt +47 -0
- data/lib/assets/static/js/2.99b8c933.chunk.js.map +1 -0
- data/lib/assets/static/js/2.bbbcdbd6.chunk.js +3 -0
- data/lib/assets/static/js/2.bbbcdbd6.chunk.js.LICENSE.txt +41 -0
- data/lib/assets/static/js/2.bbbcdbd6.chunk.js.map +1 -0
- data/lib/assets/static/js/2.d996d4ae.chunk.js +3 -0
- data/lib/assets/static/js/2.d996d4ae.chunk.js.LICENSE.txt +41 -0
- data/lib/assets/static/js/2.d996d4ae.chunk.js.map +1 -0
- data/lib/assets/static/js/3.27d693f5.chunk.js +2 -0
- data/lib/assets/static/js/3.27d693f5.chunk.js.map +1 -0
- data/lib/assets/static/js/3.29ce1833.chunk.js +2 -0
- data/lib/assets/static/js/3.29ce1833.chunk.js.map +1 -0
- data/lib/assets/static/js/3.566901ad.chunk.js +2 -0
- data/lib/assets/static/js/3.566901ad.chunk.js.map +1 -0
- data/lib/assets/static/js/3.996d9368.chunk.js +2 -0
- data/lib/assets/static/js/3.996d9368.chunk.js.map +1 -0
- data/lib/assets/static/js/3.ee90b0ac.chunk.js +2 -0
- data/lib/assets/static/js/3.ee90b0ac.chunk.js.map +1 -0
- data/lib/assets/static/js/3.f6dcabfc.chunk.js +2 -0
- data/lib/assets/static/js/3.f6dcabfc.chunk.js.map +1 -0
- data/lib/assets/static/js/main.06049a6c.chunk.js +2 -0
- data/lib/assets/static/js/main.06049a6c.chunk.js.map +1 -0
- data/lib/assets/static/js/main.0d902f02.chunk.js +2 -0
- data/lib/assets/static/js/main.0d902f02.chunk.js.map +1 -0
- data/lib/assets/static/js/main.1aaab429.chunk.js +2 -0
- data/lib/assets/static/js/main.1aaab429.chunk.js.map +1 -0
- data/lib/assets/static/js/main.2d0b71bd.chunk.js +2 -0
- data/lib/assets/static/js/main.2d0b71bd.chunk.js.map +1 -0
- data/lib/assets/static/js/main.5b37e0b8.chunk.js +2 -0
- data/lib/assets/static/js/main.5b37e0b8.chunk.js.map +1 -0
- data/lib/assets/static/js/main.6d8f3ae8.chunk.js +2 -0
- data/lib/assets/static/js/main.6d8f3ae8.chunk.js.map +1 -0
- data/lib/assets/static/js/main.7725e8ca.chunk.js +2 -0
- data/lib/assets/static/js/main.7725e8ca.chunk.js.map +1 -0
- data/lib/assets/static/js/main.7c6faf79.chunk.js +2 -0
- data/lib/assets/static/js/main.7c6faf79.chunk.js.map +1 -0
- data/lib/assets/static/js/main.7d2ac052.chunk.js +2 -0
- data/lib/assets/static/js/main.7d2ac052.chunk.js.map +1 -0
- data/lib/assets/static/js/main.7d7d3506.chunk.js +2 -0
- data/lib/assets/static/js/main.7d7d3506.chunk.js.map +1 -0
- data/lib/assets/static/js/main.93ba19ed.chunk.js +2 -0
- data/lib/assets/static/js/main.93ba19ed.chunk.js.map +1 -0
- data/lib/assets/static/js/main.9d0e4106.chunk.js +2 -0
- data/lib/assets/static/js/main.9d0e4106.chunk.js.map +1 -0
- data/lib/assets/static/js/main.9df3330b.chunk.js +2 -0
- data/lib/assets/static/js/main.9df3330b.chunk.js.map +1 -0
- data/lib/assets/static/js/main.b7479be0.chunk.js +2 -0
- data/lib/assets/static/js/main.b7479be0.chunk.js.map +1 -0
- data/lib/assets/static/js/main.c9276c68.chunk.js +2 -0
- data/lib/assets/static/js/main.c9276c68.chunk.js.map +1 -0
- data/lib/assets/static/js/main.d85be3fe.chunk.js +2 -0
- data/lib/assets/static/js/main.d85be3fe.chunk.js.map +1 -0
- data/lib/assets/static/js/main.d9e659d7.chunk.js +2 -0
- data/lib/assets/static/js/main.d9e659d7.chunk.js.map +1 -0
- data/lib/assets/static/js/main.dace488a.chunk.js +2 -0
- data/lib/assets/static/js/main.dace488a.chunk.js.map +1 -0
- data/lib/assets/static/js/main.f3fd366c.chunk.js +2 -0
- data/lib/assets/static/js/main.f3fd366c.chunk.js.map +1 -0
- data/lib/assets/static/js/main.f686dbca.chunk.js +2 -0
- data/lib/assets/static/js/main.f686dbca.chunk.js.map +1 -0
- data/lib/assets/static/js/runtime-main.38f920d2.js +2 -0
- data/lib/assets/static/js/runtime-main.38f920d2.js.map +1 -0
- data/lib/assets/static/js/runtime-main.5aecb345.js +2 -0
- data/lib/assets/static/js/runtime-main.5aecb345.js.map +1 -0
- data/lib/assets/static/js/runtime-main.63c7a71d.js +2 -0
- data/lib/assets/static/js/runtime-main.63c7a71d.js.map +1 -0
- data/lib/assets/static/js/runtime-main.d938a5a3.js +2 -0
- data/lib/assets/static/js/runtime-main.d938a5a3.js.map +1 -0
- data/lib/assets/static/js/runtime-main.e9b43cb3.js +2 -0
- data/lib/assets/static/js/runtime-main.e9b43cb3.js.map +1 -0
- data/lib/assets/static/js/runtime-main.fa834e43.js +2 -0
- data/lib/assets/static/js/runtime-main.fa834e43.js.map +1 -0
- data/lib/assets/static/media/SpecialElite-Regular.9dc7a59a.ttf +0 -0
- data/lib/assets/static/media/logo.6ce24c58.svg +1 -0
- data/lib/factory_burgers.rb +13 -0
- data/lib/factory_burgers/app.rb +17 -0
- data/lib/factory_burgers/builder.rb +32 -0
- data/lib/factory_burgers/cheating.rb +39 -0
- data/lib/factory_burgers/factory_bot_adapter.rb +44 -0
- data/lib/factory_burgers/init.rb +9 -0
- data/lib/factory_burgers/introspection.rb +31 -0
- data/lib/factory_burgers/middleware/build.rb +62 -0
- data/lib/factory_burgers/middleware/data.rb +17 -0
- data/lib/factory_burgers/middleware/static.rb +35 -0
- data/lib/factory_burgers/models/factory.rb +98 -0
- data/lib/factory_burgers/models/factory_output.rb +38 -0
- data/lib/factory_burgers/presenter_builder.rb +41 -0
- data/lib/factory_burgers/presenters.rb +46 -0
- data/lib/factory_burgers/presenters/base.rb +29 -0
- data/lib/factory_burgers/sequence_cheater.rb +28 -0
- data/lib/factory_burgers/sequence_injector.rb +25 -0
- metadata +251 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
module FactoryBotAdapter
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def factory_bot
|
6
|
+
FactoryBot
|
7
|
+
end
|
8
|
+
|
9
|
+
def version
|
10
|
+
factory_boy::VERSION
|
11
|
+
end
|
12
|
+
|
13
|
+
def numeric_version
|
14
|
+
verion.split(".").map(&:to_i)
|
15
|
+
end
|
16
|
+
|
17
|
+
def major_version
|
18
|
+
numeric_versionnn.first
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: support non-v6 versions
|
22
|
+
def load_factories
|
23
|
+
FactoryBot::V6.load_factories
|
24
|
+
end
|
25
|
+
|
26
|
+
def factories
|
27
|
+
FactoryBot::Internal.factories
|
28
|
+
end
|
29
|
+
|
30
|
+
def sequences
|
31
|
+
FactoryBot::Internal.sequences
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module FactoryBotAdapter
|
36
|
+
module FactoryBot::V6
|
37
|
+
module_function
|
38
|
+
|
39
|
+
def load_factories
|
40
|
+
FactoryBurgers::FactoryBotAdapter.factory_bot.reload
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
module Introspection
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def factories
|
6
|
+
FactoryBot::Internal.factories.sort_by(&:name)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Return a list of factories for a model instance's associations
|
10
|
+
def association_factories(klass)
|
11
|
+
buildable_associations(klass).flat_map do |assoc|
|
12
|
+
factories_for_class(assoc.klass).map do |factory|
|
13
|
+
{
|
14
|
+
association: assoc,
|
15
|
+
factory: factory,
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def factories_for_class(klass)
|
22
|
+
factories.select do |factory|
|
23
|
+
factory.build_class.ancestors.include?(klass)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def buildable_associations(klass)
|
28
|
+
klass.reflect_on_all_associations.reject { |assoc| assoc.is_a?(ActiveRecord::Reflection::ThroughReflection) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module FactoryBurgers
|
5
|
+
module Middleware
|
6
|
+
# TODO: extract controller methods into controller-like classes
|
7
|
+
class Build
|
8
|
+
def call(env)
|
9
|
+
params = paramters(env)
|
10
|
+
factory = params.fetch("factory")
|
11
|
+
traits = params["traits"]&.keys
|
12
|
+
attributes = attribute_overrides(params)
|
13
|
+
owner = get_resource_owner(params)
|
14
|
+
resource = FactoryBurgers::Builder.new.build(factory, traits, attributes, owner)
|
15
|
+
object_data = FactoryBurgers::Models::FactoryOutput.new(resource).data
|
16
|
+
response_data = {ok: true, data: object_data}
|
17
|
+
return [200, {"Content-Type" => "application/json"}, [JSON.dump(response_data)]]
|
18
|
+
rescue ActiveRecord::RecordInvalid => err
|
19
|
+
log_error(err)
|
20
|
+
return [422, {"Content-Type" => "application/json"}, [JSON.dump({ok: false, error: err.message})]]
|
21
|
+
rescue StandardError => err
|
22
|
+
log_error(err)
|
23
|
+
return [500, {"Content-Type" => "application/json"}, [JSON.dump({ok: false, error: err.message})]]
|
24
|
+
end
|
25
|
+
|
26
|
+
def request(env)
|
27
|
+
Rack::Request.new(env)
|
28
|
+
end
|
29
|
+
|
30
|
+
def paramters(env)
|
31
|
+
request(env).params
|
32
|
+
end
|
33
|
+
|
34
|
+
def attribute_overrides(params)
|
35
|
+
attribute_items = params["attributes"] || []
|
36
|
+
attribute_items = attribute_items.reject{ |attr| !attr["name"].present? }
|
37
|
+
return attribute_items.map { |attr| [attr["name"], attr["value"]] }.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
# TODO: make params explicit
|
41
|
+
def get_resource_owner(params)
|
42
|
+
return nil if params[:owner_type].blank? || params[:owner_id].blank? || params[:owner_association].blank?
|
43
|
+
|
44
|
+
valid_owner_types = ActiveRecord::Base.descendants.map(&:name)
|
45
|
+
raise "Danger, will Robinson! #{params[:owner_type]} is an impostor!" if !valid_owner_types.include?(params[:owner_type])
|
46
|
+
|
47
|
+
klass = params[:owner_type].constantize
|
48
|
+
raise "Danger, will Robinson! #{params[:owner_association]} is an impostor!" if !klass.reflections.include?(params[:owner_association])
|
49
|
+
|
50
|
+
return params[:owner_type].constantize.find(params[:owner_id])
|
51
|
+
end
|
52
|
+
|
53
|
+
def log_error(error)
|
54
|
+
logger.error("#{error.class}: #{error.message}\n" + error.backtrace&.join("\n").to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def logger
|
58
|
+
@logger ||= Logger.new($stdout)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module FactoryBurgers
|
4
|
+
module Middleware
|
5
|
+
class Data
|
6
|
+
def call(env)
|
7
|
+
factories = FactoryBot.factories.sort_by(&:name)
|
8
|
+
factory_data = factories.map { |factory| factory_data(factory) }
|
9
|
+
return [200, {"Content-Type" => "application/json"}, [JSON.dump(factory_data)]]
|
10
|
+
end
|
11
|
+
|
12
|
+
def factory_data(factory)
|
13
|
+
FactoryBurgers::Models::Factory.new(factory).to_h
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
module Middleware
|
3
|
+
class Static
|
4
|
+
def call(env)
|
5
|
+
return slashpath_redirect(env["REQUEST_PATH"]) if slashpath_redirect?(env)
|
6
|
+
|
7
|
+
rack_static.call(env)
|
8
|
+
end
|
9
|
+
|
10
|
+
def slashpath_redirect?(env)
|
11
|
+
env["REQUEST_PATH"] == env["SCRIPT_NAME"] && env["REQUEST_PATH"][-1] != "/"
|
12
|
+
end
|
13
|
+
|
14
|
+
def slashpath_redirect(path)
|
15
|
+
return [
|
16
|
+
302,
|
17
|
+
{'Location' => path + "/", 'Content-Type' => 'text/html', 'Content-Length' => '0'},
|
18
|
+
[],
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def rack_static
|
23
|
+
Rack::Static.new(nil, static_options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def static_options
|
27
|
+
{urls: [""], root: asset_path, index: 'index.html'}
|
28
|
+
end
|
29
|
+
|
30
|
+
def asset_path
|
31
|
+
@asset_path ||= FactoryBurgers.root.join("assets/")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module FactoryBurgers
|
4
|
+
module Models
|
5
|
+
# TODO: support transient attributes (f.definition.attributes ...?)
|
6
|
+
# TODO: support associations
|
7
|
+
class Factory
|
8
|
+
attr_reader :factory
|
9
|
+
|
10
|
+
def initialize(factory)
|
11
|
+
@factory = factory
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
{
|
16
|
+
name: name,
|
17
|
+
class_name: class_name,
|
18
|
+
traits: traits.map(&:to_h),
|
19
|
+
attributes: attributes.map(&:to_h),
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_json(*opts, &blk)
|
24
|
+
to_h.to_json(*opts, &blk)
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
factory.name.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def class_name
|
32
|
+
build_class.base_class.name
|
33
|
+
end
|
34
|
+
|
35
|
+
def traits
|
36
|
+
defined_traits.map { |trait| Trait.new(trait) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def attributes
|
40
|
+
settable_columns.map { |col| Attribute.new(col) }
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def build_class
|
46
|
+
factory.build_class
|
47
|
+
end
|
48
|
+
|
49
|
+
def settable_columns
|
50
|
+
factory.build_class.columns.reject { |col| col.name == build_class.primary_key }
|
51
|
+
end
|
52
|
+
|
53
|
+
def defined_traits
|
54
|
+
factory.definition.defined_traits
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Attribute
|
59
|
+
attr_reader :column
|
60
|
+
|
61
|
+
def initialize(column)
|
62
|
+
@column = column
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_h
|
66
|
+
{name: name}
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_json(*opts, &blk)
|
70
|
+
to_h.to_json(*opts, &blk)
|
71
|
+
end
|
72
|
+
|
73
|
+
def name
|
74
|
+
column.name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Trait
|
79
|
+
attr_reader :trait
|
80
|
+
|
81
|
+
def initialize(trait)
|
82
|
+
@trait = trait
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_h
|
86
|
+
{name: name}
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_json(*opts, &blk)
|
90
|
+
to_h.to_json(*opts, &blk)
|
91
|
+
end
|
92
|
+
|
93
|
+
def name
|
94
|
+
trait.name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
module Models
|
3
|
+
class FactoryOutput
|
4
|
+
attr_reader :object, :presenter
|
5
|
+
|
6
|
+
# `object` is whatever the output of `Factory#create` was
|
7
|
+
def initialize(object)
|
8
|
+
@object = object
|
9
|
+
@presenter = FactoryBurgers::Presenters.presenter_for(object)
|
10
|
+
end
|
11
|
+
|
12
|
+
def data
|
13
|
+
# TODO: Sorting by name is a UI concern; move it there.
|
14
|
+
sorted_assocs = association_factories.sort_by { |item| item[:association].name }
|
15
|
+
# TODO: group type, attributes, and link into `object`, move keys into presenter
|
16
|
+
return {
|
17
|
+
type: presenter.type,
|
18
|
+
attributes: presenter.attributes,
|
19
|
+
link: presenter.link_path,
|
20
|
+
association_factories: sorted_assocs.map { |item| association_factory_data(item) },
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def association_factories
|
27
|
+
FactoryBurgers::Introspection.association_factories(object.class)
|
28
|
+
end
|
29
|
+
|
30
|
+
def association_factory_data(assoc_factory)
|
31
|
+
{
|
32
|
+
association_name: assoc_factory[:association].name.to_s,
|
33
|
+
factory_name: assoc_factory[:factory].name.to_s,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
class PresenterBuilder < BasicObject
|
3
|
+
def initialize(klass)
|
4
|
+
@presenter = ::Class.new(::FactoryBurgers::Presenters::Base)
|
5
|
+
@klass = klass
|
6
|
+
end
|
7
|
+
|
8
|
+
def build(&blk)
|
9
|
+
instance_eval(&blk)
|
10
|
+
return @presenter
|
11
|
+
end
|
12
|
+
|
13
|
+
def presents(name)
|
14
|
+
@presetner.presents(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def type(&blk)
|
18
|
+
@presenter.define_method(:type) do
|
19
|
+
blk.call(object)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def type(&blk)
|
24
|
+
@presenter.define_method(:type) do
|
25
|
+
blk.call(object)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def attributes(&blk)
|
30
|
+
@presenter.define_method(:attributes) do
|
31
|
+
blk.call(object)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def link_path(&blk)
|
36
|
+
@presenter.define_method(:link_path) do
|
37
|
+
blk.call(object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
module Presenters
|
3
|
+
@presenters = {}
|
4
|
+
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def present(klass, with: nil, &blk)
|
8
|
+
raise ArgumentError, "Provide `with` or block, but not both" if with && blk
|
9
|
+
|
10
|
+
presenter = with || build_presenter(klass, &blk)
|
11
|
+
@presenters[klass.to_s] = presenter
|
12
|
+
end
|
13
|
+
|
14
|
+
def purge!
|
15
|
+
@links = {}
|
16
|
+
@presenters = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def presenter_for(object)
|
20
|
+
presenter_class_for(object).new(object)
|
21
|
+
end
|
22
|
+
|
23
|
+
def presenter_class_for(object)
|
24
|
+
matching_class = object.class.ancestors.map(&:name).find do |class_name|
|
25
|
+
@presenters.key?(class_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
return matching_class ? @presenters[matching_class] : FactoryBurgers::Presenters::Base
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO use this from FactoryOutput
|
32
|
+
def data_for(object)
|
33
|
+
presenter = presenter_for(object) or return nil
|
34
|
+
{
|
35
|
+
type: presenter.type,
|
36
|
+
attribuets: presenter.attributes,
|
37
|
+
link: presenter.link_path,
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
# block provided to `present`; build a presenter class
|
42
|
+
def build_presenter(klass, &blk)
|
43
|
+
PresenterBuilder.new(klass).build(&blk)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FactoryBurgers
|
2
|
+
module Presenters
|
3
|
+
class Base
|
4
|
+
class << self
|
5
|
+
def presents(name)
|
6
|
+
define_method(name) { object }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :object
|
11
|
+
|
12
|
+
def initialize(object)
|
13
|
+
@object = object
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
object.class.name
|
18
|
+
end
|
19
|
+
|
20
|
+
def attributes
|
21
|
+
object.attributes.slice("id", "name")
|
22
|
+
end
|
23
|
+
|
24
|
+
def link_path
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|