kashmir 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.
@@ -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