kashmir 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,108 @@
1
+ require 'test_helper'
2
+
3
+ describe Kashmir::InlineDsl do
4
+
5
+ module InlineDSLTesting
6
+ class Recipe < OpenStruct
7
+ include Kashmir
8
+
9
+ representations do
10
+ rep(:num_steps)
11
+ rep(:title)
12
+ rep(:chef)
13
+ end
14
+ end
15
+
16
+ class Chef < OpenStruct
17
+ include Kashmir
18
+
19
+ representations do
20
+ rep(:full_name)
21
+ rep(:award)
22
+ end
23
+
24
+ def full_name
25
+ "#{first_name} #{last_name}"
26
+ end
27
+ end
28
+
29
+ class Award < OpenStruct
30
+ include Kashmir
31
+
32
+ representations do
33
+ base([:name, :year])
34
+ end
35
+ end
36
+ end
37
+
38
+ before do
39
+ @award = InlineDSLTesting::Award.new(name: 'Best Chef', year: 2015)
40
+ @chef = InlineDSLTesting::Chef.new(first_name: 'Netto', last_name: 'Farah', award: @award)
41
+ @brisket = InlineDSLTesting::Recipe.new(title: 'BBQ Brisket', num_steps: 2, chef: @chef)
42
+ end
43
+
44
+ it 'creates an inline representer' do
45
+ inline_representer = Kashmir::InlineDsl.build do
46
+ prop :num_steps
47
+ prop :title
48
+ end
49
+
50
+ assert_equal inline_representer.definitions, [:num_steps, :title]
51
+
52
+ cooked_brisket = @brisket.represent(inline_representer.definitions)
53
+ assert_equal cooked_brisket, { title: 'BBQ Brisket', num_steps: 2 }
54
+ end
55
+
56
+ describe 'Reduced syntax' do
57
+
58
+ describe '#represent_with' do
59
+ it 'works with flat representers' do
60
+ cooked_brisket = @brisket.represent_with do
61
+ prop :title
62
+ prop :num_steps
63
+ end
64
+
65
+ assert_equal cooked_brisket, { title: 'BBQ Brisket', num_steps: 2 }
66
+ end
67
+
68
+ it 'works with nested representers' do
69
+ cooked_brisket = @brisket.represent_with do
70
+ prop :title
71
+ prop :num_steps
72
+
73
+ inline :chef do
74
+ prop :full_name
75
+ end
76
+ end
77
+
78
+ assert_equal cooked_brisket, {
79
+ title: 'BBQ Brisket',
80
+ num_steps: 2,
81
+ chef: {
82
+ full_name: 'Netto Farah'
83
+ }
84
+ }
85
+ end
86
+ end
87
+
88
+ it 'works with multi level nested representers' do
89
+ cooked_brisket = @brisket.represent_with do
90
+ prop :title
91
+ inline :chef do
92
+ prop :full_name
93
+ inline :award
94
+ end
95
+ end
96
+
97
+ assert_equal cooked_brisket, {
98
+ title: 'BBQ Brisket',
99
+ chef: {
100
+ full_name: 'Netto Farah',
101
+ award: {
102
+ name: 'Best Chef', year: 2015
103
+ }
104
+ }
105
+ }
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,216 @@
1
+ require 'test_helper'
2
+
3
+ describe Kashmir do
4
+
5
+ class Recipe < OpenStruct
6
+ include Kashmir
7
+
8
+ representations do
9
+ base([:title, :preparation_time])
10
+ rep(:num_steps)
11
+ rep(:chef)
12
+ end
13
+
14
+ def num_steps
15
+ steps.size
16
+ end
17
+ end
18
+
19
+ class Chef < OpenStruct
20
+ include Kashmir
21
+
22
+ representations do
23
+ base([:name])
24
+ end
25
+ end
26
+
27
+ before(:each) do
28
+ @recipe = Recipe.new(title: 'Beef stew', preparation_time: 60)
29
+ @chef = Chef.new(name: 'Netto')
30
+ end
31
+
32
+ it 'renders basic attribute representations' do
33
+ assert_equal @recipe.represent, { title: 'Beef stew', preparation_time: 60 }
34
+ end
35
+
36
+ it 'renders basic calculated representations' do
37
+ @recipe.steps = ['chop', 'cook']
38
+ assert_equal @recipe.represent([:num_steps]), {
39
+ title: 'Beef stew',
40
+ preparation_time: 60,
41
+ num_steps: 2
42
+ }
43
+ end
44
+
45
+ it 'renders nested representations' do
46
+ @recipe.chef = @chef
47
+ representation = @recipe.represent([:chef])
48
+ assert_equal representation[:chef], { name: 'Netto' }
49
+ end
50
+ end
51
+
52
+ describe 'Complex Representations' do
53
+ class BBQRecipe < OpenStruct
54
+ include Kashmir
55
+
56
+ representations do
57
+ base([:title])
58
+ rep(:chef)
59
+ end
60
+ end
61
+
62
+ class BBQChef < OpenStruct
63
+ include Kashmir
64
+
65
+ representations do
66
+ base([:name])
67
+ rep(:restaurant)
68
+ end
69
+ end
70
+
71
+ class BBQRestaurant < OpenStruct
72
+ include Kashmir
73
+
74
+ representations do
75
+ base([:name])
76
+ rep(:rating)
77
+ end
78
+ end
79
+
80
+ before do
81
+ @bbq_joint = BBQRestaurant.new(name: "Netto's BBQ Joint", rating: '5 stars')
82
+ @netto = BBQChef.new(name: 'Netto', restaurant: @bbq_joint)
83
+ @brisket = BBQRecipe.new(title: 'BBQ Brisket', chef: @netto)
84
+ end
85
+
86
+ it 'works with base representations' do
87
+ assert_equal @netto.represent, { name: 'Netto' }
88
+ assert_equal @brisket.represent, { title: 'BBQ Brisket' }
89
+ assert_equal @bbq_joint.represent, { name: "Netto's BBQ Joint" }
90
+ end
91
+
92
+ it 'works with simple nesting' do
93
+ representation = @netto.represent([:restaurant])
94
+ assert_equal representation, {
95
+ name: 'Netto',
96
+ restaurant: { name: "Netto's BBQ Joint" }
97
+ }
98
+ end
99
+
100
+ it 'allows clients to customize nested representations' do
101
+ representation = @netto.represent [{ :restaurant => [:rating] }]
102
+
103
+ assert_equal representation, {
104
+ name: 'Netto',
105
+ restaurant: { name: "Netto's BBQ Joint", rating: '5 stars' }
106
+ }
107
+ end
108
+
109
+ it 'allows clients to create complex representation trees' do
110
+ representation = @brisket.represent([
111
+ :chef => [
112
+ { :restaurant => [ :rating ] }
113
+ ]
114
+ ])
115
+
116
+ assert_equal representation, {
117
+ title: 'BBQ Brisket',
118
+ chef: {
119
+ name: 'Netto',
120
+ restaurant: {
121
+ name: "Netto's BBQ Joint",
122
+ rating: '5 stars'
123
+ }
124
+ }
125
+ }
126
+ end
127
+ end
128
+
129
+ describe 'Collections' do
130
+
131
+ class Ingredient < OpenStruct
132
+ include Kashmir
133
+
134
+ representations do
135
+ rep(:name)
136
+ rep(:quantity)
137
+ end
138
+ end
139
+
140
+ class ClassyRecipe < OpenStruct
141
+ include Kashmir
142
+
143
+ representations do
144
+ rep(:title)
145
+ rep(:ingredients)
146
+ end
147
+ end
148
+
149
+ before(:each) do
150
+ @omelette = ClassyRecipe.new(title: 'Omelette Du Fromage')
151
+ @omelette.ingredients = [
152
+ Ingredient.new(name: 'Egg', quantity: 2),
153
+ Ingredient.new(name: 'Cheese', quantity: 'a lot!')
154
+ ]
155
+ end
156
+
157
+ it 'represents collections' do
158
+ nice_omelette = @omelette.represent([:title, { :ingredients => [ :name, :quantity ]}])
159
+
160
+ assert_equal nice_omelette, {
161
+ title: 'Omelette Du Fromage',
162
+ ingredients: [
163
+ { name: 'Egg', quantity: 2 },
164
+ { name: 'Cheese', quantity: 'a lot!' }
165
+ ]
166
+ }
167
+ end
168
+ end
169
+
170
+ describe "Hashes" do
171
+
172
+ class RecipeCategories < OpenStruct
173
+ include Kashmir
174
+
175
+ representations do
176
+ rep :categories
177
+ end
178
+ end
179
+
180
+ before(:each) do
181
+ @omelette = ClassyRecipe.new(title: 'Omelette Du Fromage')
182
+ @scrambled_eggs = ClassyRecipe.new(title: 'Scrambled Eggs')
183
+
184
+ @brisket = ClassyRecipe.new(title: 'Briksket')
185
+ @ribs = ClassyRecipe.new(title: 'BBQ Ribs')
186
+
187
+ @categories = [
188
+ { name: 'Breakfast', recipes: [ @omelette, @scrambled_eggs] },
189
+ { name: 'Dinner', recipes: [ @brisket, @ribs ] }
190
+ ]
191
+ end
192
+
193
+ it 'represents hashes' do
194
+ representation = RecipeCategories.new(categories: @categories).represent([{
195
+ categories: [
196
+ :name,
197
+ recipes: [:title]
198
+ ]
199
+ }])
200
+
201
+ assert_equal representation, {
202
+ categories: [
203
+ {
204
+ name: "Breakfast", recipes: [
205
+ { title: "Omelette Du Fromage" }, { title: "Scrambled Eggs" }
206
+ ]
207
+ },
208
+ {
209
+ name: "Dinner", recipes: [
210
+ { title: "Briksket" }, { title: "BBQ Ribs" }
211
+ ]
212
+ }
213
+ ]
214
+ }
215
+ end
216
+ end
@@ -0,0 +1,69 @@
1
+ module AR
2
+ class Recipe < ActiveRecord::Base
3
+ include Kashmir
4
+
5
+ belongs_to :chef
6
+ has_many :recipes_ingredients
7
+ has_many :ingredients, through: :recipes_ingredients
8
+
9
+ representations do
10
+ rep :title
11
+ rep :chef
12
+ rep :ingredients
13
+ end
14
+ end
15
+
16
+ class Ingredient < ActiveRecord::Base
17
+ include Kashmir
18
+
19
+ representations do
20
+ rep :name
21
+ rep :quantity
22
+ end
23
+ end
24
+
25
+ class RecipesIngredient < ActiveRecord::Base
26
+ belongs_to :recipe
27
+ belongs_to :ingredient
28
+ end
29
+
30
+ class Restaurant < ActiveRecord::Base
31
+ include Kashmir
32
+
33
+ belongs_to :owner, class_name: 'Chef'
34
+ has_one :rating
35
+
36
+ representations do
37
+ rep :name
38
+ rep :owner
39
+ rep :rating
40
+
41
+ rep :current_customer_count, cacheable: false
42
+ end
43
+ end
44
+
45
+ class Rating < ActiveRecord::Base
46
+ include Kashmir
47
+
48
+ belongs_to :restaurant
49
+
50
+ representations do
51
+ rep :value
52
+ end
53
+ end
54
+
55
+ class Chef < ActiveRecord::Base
56
+ include Kashmir
57
+
58
+ has_many :recipes
59
+ has_many :ingredients, through: :recipes
60
+ has_one :restaurant, foreign_key: 'owner_id'
61
+
62
+ representations do
63
+ rep :name
64
+ rep :recipes
65
+ rep :ingredients
66
+ rep :restaurant
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,33 @@
1
+ module TestData
2
+ def self.create_tom
3
+ AR::Chef.create(name: 'Tom').tap do |tom|
4
+ AR::Recipe.create(title: 'Pastrami Sandwich', chef: tom).tap do |r|
5
+ r.ingredients.create(name: 'Pastrami', quantity: 'a lot')
6
+ r.ingredients.create(name: 'Cheese', quantity: '1 slice')
7
+ end
8
+
9
+ AR::Recipe.create(title: 'Belly Burger', chef: tom).tap do |r|
10
+ r.ingredients.create(name: 'Pork Belly', quantity: 'plenty')
11
+ r.ingredients.create(name: 'Green Apple', quantity: '2 slices')
12
+ end
13
+
14
+ AR::Restaurant.create(name: 'Chef Tom Belly Burgers', owner: tom) do |res|
15
+ res.create_rating(value: '3 stars')
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.create_netto
21
+ AR::Chef.create(name: 'Netto').tap do |netto|
22
+ AR::Recipe.create(title: 'Turkey Sandwich', chef: netto).tap do |r|
23
+ r.ingredients.create(name: 'Turkey', quantity: 'a lot')
24
+ r.ingredients.create(name: 'Cheese', quantity: '1 slice')
25
+ end
26
+
27
+ AR::Recipe.create(title: 'Cheese Burger', chef: netto).tap do |r|
28
+ r.ingredients.create(name: 'Patty', quantity: '1')
29
+ r.ingredients.create(name: 'Cheese', quantity: '2 slices')
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :recipes, force: true do |t|
3
+ t.column :title, :string
4
+ t.column :num_steps, :integer
5
+ t.column :chef_id, :integer
6
+ end
7
+
8
+ create_table :ingredients, force: true do |t|
9
+ t.column :name, :string
10
+ t.column :quantity, :string
11
+ end
12
+
13
+ create_table :recipes_ingredients, force: true do |t|
14
+ t.column :recipe_id, :integer
15
+ t.column :ingredient_id, :integer
16
+ end
17
+
18
+ create_table :chefs, force: true do |t|
19
+ t.column :name, :string
20
+ end
21
+
22
+ create_table :restaurants, force: true do |t|
23
+ t.column :name, :string
24
+ t.column :owner_id, :integer
25
+ t.column :current_customer_count, :integer
26
+ end
27
+
28
+ create_table :ratings, force: true do |t|
29
+ t.column :value, :string
30
+ t.column :restaurant_id, :integer
31
+ end
32
+ end