dugway 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +3 -0
  3. data/Gemfile +2 -0
  4. data/README.md +151 -0
  5. data/Rakefile +12 -0
  6. data/bin/dugway +7 -0
  7. data/dugway.gemspec +43 -0
  8. data/lib/dugway.rb +66 -0
  9. data/lib/dugway/application.rb +147 -0
  10. data/lib/dugway/cart.rb +144 -0
  11. data/lib/dugway/cli.rb +22 -0
  12. data/lib/dugway/cli/build.rb +56 -0
  13. data/lib/dugway/cli/create.rb +71 -0
  14. data/lib/dugway/cli/server.rb +37 -0
  15. data/lib/dugway/cli/templates/Gemfile.tt +2 -0
  16. data/lib/dugway/cli/templates/config.tt +24 -0
  17. data/lib/dugway/cli/templates/gitignore.tt +9 -0
  18. data/lib/dugway/cli/templates/source/cart.html +40 -0
  19. data/lib/dugway/cli/templates/source/checkout.html +33 -0
  20. data/lib/dugway/cli/templates/source/contact.html +37 -0
  21. data/lib/dugway/cli/templates/source/home.html +25 -0
  22. data/lib/dugway/cli/templates/source/images/badge.png +0 -0
  23. data/lib/dugway/cli/templates/source/javascripts/cart.js.coffee +7 -0
  24. data/lib/dugway/cli/templates/source/javascripts/product.js.coffee +7 -0
  25. data/lib/dugway/cli/templates/source/layout.html +101 -0
  26. data/lib/dugway/cli/templates/source/maintenance.html +20 -0
  27. data/lib/dugway/cli/templates/source/product.html +65 -0
  28. data/lib/dugway/cli/templates/source/products.html +25 -0
  29. data/lib/dugway/cli/templates/source/screenshot.jpg +0 -0
  30. data/lib/dugway/cli/templates/source/scripts.js +19 -0
  31. data/lib/dugway/cli/templates/source/settings.json +71 -0
  32. data/lib/dugway/cli/templates/source/styles.css +27 -0
  33. data/lib/dugway/cli/templates/source/stylesheets/cart.css.sass +38 -0
  34. data/lib/dugway/cli/templates/source/stylesheets/layout.css.sass +103 -0
  35. data/lib/dugway/cli/templates/source/stylesheets/product.css.sass +19 -0
  36. data/lib/dugway/cli/templates/source/stylesheets/products.css.sass +20 -0
  37. data/lib/dugway/cli/templates/source/stylesheets/vendor/normalize.css +396 -0
  38. data/lib/dugway/cli/templates/source/success.html +5 -0
  39. data/lib/dugway/controller.rb +148 -0
  40. data/lib/dugway/data/locales/cs.yml +26 -0
  41. data/lib/dugway/data/locales/da.yml +26 -0
  42. data/lib/dugway/data/locales/en-AU.yml +26 -0
  43. data/lib/dugway/data/locales/en-GB.yml +26 -0
  44. data/lib/dugway/data/locales/en-PH.yml +27 -0
  45. data/lib/dugway/data/locales/en-US.yml +26 -0
  46. data/lib/dugway/data/locales/es-MX.yml +26 -0
  47. data/lib/dugway/data/locales/eu.yml +26 -0
  48. data/lib/dugway/data/locales/gsw-CH.yml +26 -0
  49. data/lib/dugway/data/locales/hu.yml +26 -0
  50. data/lib/dugway/data/locales/il.yml +26 -0
  51. data/lib/dugway/data/locales/ja.yml +30 -0
  52. data/lib/dugway/data/locales/ms-MY.yml +26 -0
  53. data/lib/dugway/data/locales/nb.yml +22 -0
  54. data/lib/dugway/data/locales/pl.yml +27 -0
  55. data/lib/dugway/data/locales/pt-BR.yml +26 -0
  56. data/lib/dugway/data/locales/sv-SE.yml +26 -0
  57. data/lib/dugway/data/locales/th.yml +26 -0
  58. data/lib/dugway/data/locales/tr.yml +29 -0
  59. data/lib/dugway/data/locales/zh-TW.yml +30 -0
  60. data/lib/dugway/data/theme_fonts.yml +151 -0
  61. data/lib/dugway/extensions/time.rb +15 -0
  62. data/lib/dugway/liquid/drops/account_drop.rb +17 -0
  63. data/lib/dugway/liquid/drops/artist_drop.rb +9 -0
  64. data/lib/dugway/liquid/drops/artists_drop.rb +13 -0
  65. data/lib/dugway/liquid/drops/base_drop.rb +59 -0
  66. data/lib/dugway/liquid/drops/cart_drop.rb +13 -0
  67. data/lib/dugway/liquid/drops/cart_item_drop.rb +21 -0
  68. data/lib/dugway/liquid/drops/categories_drop.rb +13 -0
  69. data/lib/dugway/liquid/drops/category_drop.rb +9 -0
  70. data/lib/dugway/liquid/drops/contact_drop.rb +29 -0
  71. data/lib/dugway/liquid/drops/country_drop.rb +6 -0
  72. data/lib/dugway/liquid/drops/currency_drop.rb +6 -0
  73. data/lib/dugway/liquid/drops/image_drop.rb +6 -0
  74. data/lib/dugway/liquid/drops/page_drop.rb +13 -0
  75. data/lib/dugway/liquid/drops/pages_drop.rb +9 -0
  76. data/lib/dugway/liquid/drops/product_drop.rb +101 -0
  77. data/lib/dugway/liquid/drops/product_option_drop.rb +27 -0
  78. data/lib/dugway/liquid/drops/products_drop.rb +75 -0
  79. data/lib/dugway/liquid/drops/shipping_option_drop.rb +13 -0
  80. data/lib/dugway/liquid/drops/theme_drop.rb +23 -0
  81. data/lib/dugway/liquid/filters/comparison_filters.rb +48 -0
  82. data/lib/dugway/liquid/filters/core_filters.rb +138 -0
  83. data/lib/dugway/liquid/filters/default_pagination.rb +35 -0
  84. data/lib/dugway/liquid/filters/font_filters.rb +9 -0
  85. data/lib/dugway/liquid/filters/url_filters.rb +66 -0
  86. data/lib/dugway/liquid/filters/util_filters.rb +119 -0
  87. data/lib/dugway/liquid/tags/checkout_form.rb +9 -0
  88. data/lib/dugway/liquid/tags/get.rb +58 -0
  89. data/lib/dugway/liquid/tags/paginate.rb +129 -0
  90. data/lib/dugway/liquifier.rb +122 -0
  91. data/lib/dugway/logger.rb +16 -0
  92. data/lib/dugway/request.rb +36 -0
  93. data/lib/dugway/store.rb +166 -0
  94. data/lib/dugway/template.rb +44 -0
  95. data/lib/dugway/theme.rb +145 -0
  96. data/lib/dugway/theme_font.rb +68 -0
  97. data/lib/dugway/version.rb +3 -0
  98. data/spec/fixtures/store/page/about-us.js +1 -0
  99. data/spec/fixtures/store/products.js +1 -0
  100. data/spec/fixtures/store/store.js +1 -0
  101. data/spec/fixtures/theme/cart.html +33 -0
  102. data/spec/fixtures/theme/checkout.html +31 -0
  103. data/spec/fixtures/theme/contact.html +37 -0
  104. data/spec/fixtures/theme/home.html +38 -0
  105. data/spec/fixtures/theme/images/bc_badge.png +0 -0
  106. data/spec/fixtures/theme/javascripts/one.js +3 -0
  107. data/spec/fixtures/theme/javascripts/two.js.coffee +2 -0
  108. data/spec/fixtures/theme/layout.html +77 -0
  109. data/spec/fixtures/theme/maintenance.html +17 -0
  110. data/spec/fixtures/theme/product.html +73 -0
  111. data/spec/fixtures/theme/products.html +41 -0
  112. data/spec/fixtures/theme/screenshot.jpg +0 -0
  113. data/spec/fixtures/theme/scripts.js +2 -0
  114. data/spec/fixtures/theme/settings.json +55 -0
  115. data/spec/fixtures/theme/styles.css +4 -0
  116. data/spec/fixtures/theme/stylesheets/one.css +3 -0
  117. data/spec/fixtures/theme/stylesheets/two.css.sass +4 -0
  118. data/spec/fixtures/theme/success.html +5 -0
  119. data/spec/spec_helper.rb +24 -0
  120. data/spec/units/dugway/request_spec.rb +206 -0
  121. data/spec/units/dugway/store_spec.rb +194 -0
  122. data/spec/units/dugway/template_spec.rb +145 -0
  123. data/spec/units/dugway/theme_font_spec.rb +136 -0
  124. data/spec/units/dugway_spec.rb +9 -0
  125. metadata +549 -0
@@ -0,0 +1,13 @@
1
+ module Dugway
2
+ module Drops
3
+ class ArtistsDrop < BaseDrop
4
+ def all
5
+ @all ||= source
6
+ end
7
+
8
+ def active
9
+ @active ||= source.reject { |a| store.artist_products(a['permalink']).empty? }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,59 @@
1
+ module Dugway
2
+ module Drops
3
+ class BaseDrop < Liquid::Drop
4
+ attr_reader :source
5
+ attr_reader :request
6
+ attr_reader :params
7
+
8
+ def initialize(source=nil)
9
+ @source = source
10
+ end
11
+
12
+ def context=(current_context)
13
+ @request = current_context.registers[:request]
14
+ @params = current_context.registers[:params]
15
+ super
16
+ end
17
+
18
+ def store
19
+ Dugway.store
20
+ end
21
+
22
+ def theme
23
+ Dugway.theme
24
+ end
25
+
26
+ def cart
27
+ Dugway.cart
28
+ end
29
+
30
+ def before_method(method_or_key)
31
+ if respond_to?(method_or_key)
32
+ # don't do anything, just let it default here
33
+ elsif source.respond_to?(method_or_key)
34
+ return source.send(method_or_key)
35
+ elsif source.respond_to?('has_key?') && source.has_key?(method_or_key)
36
+ return source[method_or_key]
37
+ elsif source.is_a?(Array) && source.first.has_key?('permalink')
38
+ for item in source
39
+ return item if item['permalink'] == method_or_key.to_s
40
+ end
41
+ end
42
+
43
+ nil
44
+ end
45
+
46
+ def method_missing(method, *args, &block)
47
+ before_method(method.to_s)
48
+ end
49
+
50
+ def errors
51
+ @context['errors']
52
+ end
53
+
54
+ def error(msg)
55
+ errors << msg
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ module Dugway
2
+ module Drops
3
+ class CartDrop < BaseDrop
4
+ def items
5
+ @items ||= source.items.map { |item| CartItemDrop.new(item) }
6
+ end
7
+
8
+ def price
9
+ nil # price is deprecated in favor of subtotal
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Dugway
2
+ module Drops
3
+ class CartItemDrop < BaseDrop
4
+ def price
5
+ unit_price * quantity
6
+ end
7
+
8
+ def product
9
+ ProductDrop.new(source['product'])
10
+ end
11
+
12
+ def option
13
+ ProductOptionDrop.new(source['option'])
14
+ end
15
+
16
+ def shipping
17
+ 0.0
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module Dugway
2
+ module Drops
3
+ class CategoriesDrop < BaseDrop
4
+ def all
5
+ @all ||= source
6
+ end
7
+
8
+ def active
9
+ @active ||= source.reject { |c| store.category_products(c['permalink']).empty? }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Dugway
2
+ module Drops
3
+ class CategoryDrop < BaseDrop
4
+ def products
5
+ store.category_products(permalink).map { |p| ProductDrop.new(p) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ module Dugway
2
+ module Drops
3
+ class ContactDrop < BaseDrop
4
+ def name
5
+ params[:name] ||= ''
6
+ end
7
+
8
+ def email
9
+ params[:email] ||= ''
10
+ end
11
+
12
+ def subject
13
+ params[:subject] ||= ''
14
+ end
15
+
16
+ def message
17
+ params[:message] ||= ''
18
+ end
19
+
20
+ def captcha
21
+ %{<img id="captcha_image" src="https://s3.amazonaws.com/bigcartel/captcha/28e3d1288cbc70c0cd1a2d10845f8e11e1a90d14.png">}
22
+ end
23
+
24
+ def sent
25
+ request.path == '/contact' && request.post? && errors.blank?
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ module Dugway
2
+ module Drops
3
+ class CountryDrop < BaseDrop
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Dugway
2
+ module Drops
3
+ class CurrencyDrop < BaseDrop
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Dugway
2
+ module Drops
3
+ class ImageDrop < BaseDrop
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module Dugway
2
+ module Drops
3
+ class PageDrop < BaseDrop
4
+ def meta_description
5
+ 'Example meta description'
6
+ end
7
+
8
+ def meta_keywords
9
+ 'example, key, words'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Dugway
2
+ module Drops
3
+ class PagesDrop < BaseDrop
4
+ def all
5
+ @all ||= source.select { |page| page['category'] == 'custom' }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,101 @@
1
+ module Dugway
2
+ module Drops
3
+ class ProductDrop < BaseDrop
4
+ def price
5
+ nil # price is deprecated in favor of default_price
6
+ end
7
+
8
+ def min_price
9
+ @min_price ||= price_min_max.first
10
+ end
11
+
12
+ def max_price
13
+ @max_price ||= price_min_max.last
14
+ end
15
+
16
+ def variable_pricing
17
+ @variable_pricing ||= min_price != max_price
18
+ end
19
+
20
+ def has_default_option
21
+ @has_default_option ||= options.size == 1 && option.default
22
+ end
23
+
24
+ def option
25
+ @option ||= options.blank? ? nil : options.first
26
+ end
27
+
28
+ def options
29
+ @options ||= source['options'].each_with_index.map { |o,i| ProductOptionDrop.new(o.update('position' => i+1, 'product' => self)) }
30
+ end
31
+
32
+ def options_in_stock
33
+ @options_in_stock ||= options
34
+ end
35
+
36
+ def shipping
37
+ @shipping ||= source['shipping'].map { |o| ShippingOptionDrop.new(o.update('product' => self)) }
38
+ end
39
+
40
+ def image
41
+ @image ||= images.blank? ? nil : images.first
42
+ end
43
+
44
+ def images
45
+ @images ||= source['images'].present? ? source['images'].map { |image| ImageDrop.new(image) } : []
46
+ end
47
+
48
+ def image_count
49
+ @image_count ||= images.size
50
+ end
51
+
52
+ def previous_product
53
+ @previous_product ||= begin
54
+ if previous_product = store.previous_product(permalink)
55
+ ProductDrop.new(previous_product)
56
+ else
57
+ nil
58
+ end
59
+ end
60
+ end
61
+
62
+ def next_product
63
+ @next_product ||= begin
64
+ if next_product = store.next_product(permalink)
65
+ ProductDrop.new(next_product)
66
+ else
67
+ nil
68
+ end
69
+ end
70
+ end
71
+
72
+ def edit_url
73
+ "http://bigcartel.com"
74
+ end
75
+
76
+ def categories
77
+ @categories ||= CategoriesDrop.new(source['categories'].map { |c| CategoryDrop.new(c) }) rescue []
78
+ end
79
+
80
+ def artists
81
+ @artists ||= ArtistsDrop.new(source['artists'].map { |a| ArtistDrop.new(a) }) rescue []
82
+ end
83
+
84
+ def css_class
85
+ @css_class ||= begin
86
+ c = 'product'
87
+ c += ' sold' if status == 'sold-out'
88
+ c += ' soon' if status == 'coming-soon'
89
+ c += ' sale' if on_sale
90
+ c
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def price_min_max
97
+ @price_min_max ||= options.collect(&:price).uniq.minmax
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,27 @@
1
+ module Dugway
2
+ module Drops
3
+ class ProductOptionDrop < BaseDrop
4
+ def default
5
+ name.downcase == 'default'
6
+ end
7
+
8
+ def has_custom_price
9
+ price != product.default_price
10
+ end
11
+
12
+ # Make up inventory numbers since we obviously don't want that from the API
13
+
14
+ def quantity
15
+ @quantity ||= sold_out ? 0 : rand(100)
16
+ end
17
+
18
+ def sold
19
+ @sold ||= rand(100)
20
+ end
21
+
22
+ def inventory
23
+ ((quantity.to_f / (quantity + sold).to_f) * 100).round
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,75 @@
1
+ require 'will_paginate/array'
2
+
3
+ module Dugway
4
+ module Drops
5
+ class ProductsDrop < BaseDrop
6
+ def all
7
+ sort_and_paginate source
8
+ end
9
+
10
+ def current
11
+ sort_and_paginate begin
12
+ if artist.present?
13
+ dropify store.artist_products(artist)
14
+ elsif category.present?
15
+ dropify store.category_products(category)
16
+ elsif search_terms.present?
17
+ dropify store.search_products(search_terms)
18
+ else
19
+ source
20
+ end
21
+ end
22
+ end
23
+
24
+ def on_sale
25
+ sort_and_paginate source.select { |p| p['on_sale'] }
26
+ end
27
+
28
+ private
29
+
30
+ def order
31
+ begin case @context['internal']['order']
32
+ when 'newest', 'date'
33
+ 'date'
34
+ # We don't pass these in the API, so fake it
35
+ when 'sales', 'sells', 'views'
36
+ 'shuffle'
37
+ else
38
+ 'position'
39
+ end
40
+ end
41
+ end
42
+
43
+ def sort_and_paginate(array)
44
+ if order == 'shuffle'
45
+ array.shuffle!
46
+ elsif order == 'date'
47
+ array.sort! { |a,b| b['id'] <=> a['id'] }
48
+ else
49
+ array.sort_by! { |p| p[order] }
50
+ end
51
+
52
+ array.paginate({
53
+ :page => (@context.registers[:params][:page] || 1).to_i,
54
+ :per_page => @context['internal']['per_page']
55
+ })
56
+ end
57
+
58
+ def artist
59
+ @context.registers[:artist]['permalink'] rescue nil
60
+ end
61
+
62
+ def category
63
+ @context.registers[:category]['permalink'] rescue nil
64
+ end
65
+
66
+ def search_terms
67
+ params[:search]
68
+ end
69
+
70
+ def dropify(products)
71
+ products.map { |p| ProductDrop.new(p) }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,13 @@
1
+ module Dugway
2
+ module Drops
3
+ class ShippingOptionDrop < BaseDrop
4
+ def country
5
+ @country ||= CountryDrop.new(source['country'])
6
+ end
7
+
8
+ def strict
9
+ @strict ||= product.shipping.size > 1 || product.shipping.first.country.name.present?
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module Dugway
2
+ module Drops
3
+ class ThemeDrop < BaseDrop
4
+ def before_method(method_or_key)
5
+ if source.respond_to?('has_key?') && source.has_key?(method_or_key) && images.find { |image| image['variable'] == method_or_key.to_s }
6
+ return ImageDrop.new(source[method_or_key].stringify_keys)
7
+ end
8
+
9
+ super
10
+ end
11
+
12
+ private
13
+
14
+ def images
15
+ @images ||= settings.has_key?('images') ? settings['images'] : []
16
+ end
17
+
18
+ def settings
19
+ @settings ||= @context.registers[:settings]
20
+ end
21
+ end
22
+ end
23
+ end