padrino-fields 0.3.3

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.
Files changed (40) hide show
  1. data/.document +5 -0
  2. data/Gemfile +40 -0
  3. data/Gemfile.lock +133 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.markdown +189 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/lib/padrino-fields.rb +30 -0
  9. data/lib/padrino-fields/form_builder.rb +183 -0
  10. data/lib/padrino-fields/form_helpers.rb +63 -0
  11. data/lib/padrino-fields/orms/datamapper.rb +54 -0
  12. data/lib/padrino-fields/settings.rb +18 -0
  13. data/load_paths.rb +12 -0
  14. data/padrino-fields.gemspec +141 -0
  15. data/test/.DS_Store +0 -0
  16. data/test/fixtures/datamapper/app.rb +48 -0
  17. data/test/fixtures/datamapper/views/capture_concat.erb +14 -0
  18. data/test/fixtures/datamapper/views/capture_concat.haml +12 -0
  19. data/test/fixtures/datamapper/views/content_for.erb +11 -0
  20. data/test/fixtures/datamapper/views/content_for.haml +9 -0
  21. data/test/fixtures/datamapper/views/content_tag.erb +11 -0
  22. data/test/fixtures/datamapper/views/content_tag.haml +9 -0
  23. data/test/fixtures/datamapper/views/fields_for.erb +20 -0
  24. data/test/fixtures/datamapper/views/fields_for.haml +15 -0
  25. data/test/fixtures/datamapper/views/form_for.erb +56 -0
  26. data/test/fixtures/datamapper/views/form_for.haml +47 -0
  27. data/test/fixtures/datamapper/views/form_tag.erb +56 -0
  28. data/test/fixtures/datamapper/views/form_tag.haml +45 -0
  29. data/test/fixtures/datamapper/views/link_to.erb +5 -0
  30. data/test/fixtures/datamapper/views/link_to.haml +4 -0
  31. data/test/fixtures/datamapper/views/mail_to.erb +3 -0
  32. data/test/fixtures/datamapper/views/mail_to.haml +3 -0
  33. data/test/fixtures/datamapper/views/meta_tag.erb +3 -0
  34. data/test/fixtures/datamapper/views/meta_tag.haml +3 -0
  35. data/test/helper.rb +128 -0
  36. data/test/test_datamapper.rb +109 -0
  37. data/test/test_form_builder.rb +193 -0
  38. data/test/test_form_helpers.rb +59 -0
  39. data/test/test_settings.rb +51 -0
  40. metadata +288 -0
@@ -0,0 +1,30 @@
1
+ require 'sinatra'
2
+ require 'padrino'
3
+ require 'padrino-core/support_lite' unless defined?(SupportLite)
4
+ require 'cgi'
5
+ require 'i18n'
6
+ require 'enumerator'
7
+
8
+ FileSet.glob_require('padrino-fields/**/*.rb', __FILE__)
9
+
10
+ # Load our locales
11
+ I18n.load_path += Dir["#{File.dirname(__FILE__)}/padrino-helpers/locale/*.yml"]
12
+
13
+ module PadrinoFields
14
+ ##
15
+ # This component provides view helpers and shortcuts for generating form fields
16
+ # Should feel familiar to users of Formtastic or SimpleForm
17
+
18
+ ##
19
+ # Register Padrino::Helpers::Fields for Padrino::Application
20
+ #
21
+ class << self
22
+ def registered(app)
23
+ app.set :default_builder, 'PadrinoFieldsBuilder'
24
+ app.helpers Padrino::Helpers::FormBuilder::PadrinoFieldsBuilder
25
+ rescue
26
+ end
27
+ alias :included :registered
28
+ end
29
+
30
+ end # PadrinoFields
@@ -0,0 +1,183 @@
1
+ require 'padrino-helpers'
2
+ require File.expand_path(File.dirname(__FILE__) + '/form_helpers')
3
+ require File.expand_path(File.dirname(__FILE__) + '/orms/datamapper') if defined?(DataMapper)
4
+ require File.expand_path(File.dirname(__FILE__) + '/settings')
5
+
6
+ module Padrino
7
+ module Helpers
8
+ module FormBuilder #:nodoc:
9
+ class PadrinoFieldsBuilder < AbstractFormBuilder #:nodoc:
10
+
11
+ include PadrinoFields::Settings
12
+ include PadrinoFields::DataMapperWrapper if defined?(DataMapper)
13
+
14
+ @@settings = PadrinoFields::Settings
15
+
16
+ attr_reader :template, :object_name, :object
17
+
18
+ def input(attribute, options={})
19
+ options.reverse_merge!(:caption => options.delete(:caption)) if options[:caption]
20
+ type = options[:as] || klazz.form_column_type_for(attribute)
21
+ field_html = ""
22
+ if type == :boolean || options[:as] == :boolean
23
+ field_html << default_input(attribute,type,options)
24
+ field_html << setup_label(attribute,type,labelize(options))
25
+ else
26
+ field_html << setup_label(attribute,type,labelize(options))
27
+ field_html << default_input(attribute,type, options)
28
+ end
29
+ field_html << hint(options[:hint]) if options[:hint]
30
+ field_html << @template.error_message_on(@object,attribute,{}) if @object.errors.any?
31
+ @template.content_tag(@@settings.container, :class => css_class(attribute,type,options[:disabled])) do
32
+ field_html
33
+ end
34
+ end
35
+
36
+ def default_input(attribute,type,options={})
37
+ input_options = options.keep_if {|key, value| key != :as}
38
+ if options[:options] || options[:grouped_options]
39
+ if type==:radios || type == :checks
40
+ collect_inputs_as(attribute,type,input_options)
41
+ else
42
+ select(attribute,input_options)
43
+ end
44
+ else
45
+ singular_input_for(attribute,type,options)
46
+ end
47
+ end
48
+
49
+ %w(date email number search tel url).each do |type|
50
+ class_eval <<-EOF
51
+ ##
52
+ # Constructs a #{type} field input from the given options
53
+ #
54
+ # ==== Examples
55
+ #
56
+ # #{type}_field :username, :class => 'long'
57
+ #
58
+ def #{type}_field(field, options={})
59
+ options.reverse_merge!(:value => field_value(field), :id => field_id(field))
60
+ options.merge!(:class => field_error(field, options))
61
+ @template.#{type}_field_tag(field_name(field), options)
62
+ end
63
+ EOF
64
+ end
65
+
66
+
67
+ def collect_inputs_as(attribute,type,options={})
68
+ options[:options].map do |item|
69
+ collection_input(attribute,type,item,options.keep_if {|key, value| key != :options})
70
+ end.join("")
71
+ end
72
+
73
+ def singular_input_for(attribute,type,options={})
74
+ options.keep_if {|key, value| key != :for}
75
+ opts = html_options(attribute,type,options)
76
+ case type
77
+ when :string
78
+ case attribute
79
+ when /email/ ; email_field(attribute, opts);
80
+ when /password/ ; password_field(attribute, opts);
81
+ when /tel/,/phone/ ; tel_field(attribute, opts);
82
+ when /url/,/website/ ; url_field(attribute, opts);
83
+ when /search/ ; search_field(attribute, opts);
84
+ else ; text_field(attribute, opts);
85
+ end
86
+ when :text
87
+ text_area(attribute, opts)
88
+ when :boolean
89
+ check_box(attribute, opts)
90
+ when :date
91
+ date_field(attribute, opts)
92
+ when :file
93
+ file_field(attribute, opts)
94
+ when :number
95
+ number_field(attribute, opts)
96
+ when :radios
97
+ default_radios(attribute,type,options)
98
+ end
99
+ end
100
+
101
+ def required?(attribute)
102
+ k = klazz.is_a?(String) ? klazz.constantize : klazz
103
+ k.form_attribute_is_required?(attribute)
104
+ end
105
+
106
+ def collection_input(attribute,type,item, options={})
107
+ unchecked_value = options.delete(:uncheck_value) || '0'
108
+ options.reverse_merge!(:id => field_id(attribute), :value => '1')
109
+ options.reverse_merge!(:checked => true) if values_matches_field?(attribute, options[:value])
110
+ klass = css_class(attribute,type,options[:disabled])
111
+ name = type == :checks ? field_name(attribute) + '[]' : field_name(attribute)
112
+ if item.is_a?(Array)
113
+ text, value = item[0], item[1]
114
+ else
115
+ text = item; value = item;
116
+ end
117
+ id = field_id(attribute) + "_" + domize(text)
118
+ opts = html_options(attribute,type,options.merge(:id => id, :class => klass, :value => value))
119
+ if type == :checks
120
+ html = @template.hidden_field_tag(options[:name] || name, :value => unchecked_value, :id => nil)
121
+ input_item = @template.check_box_tag(name, opts)
122
+ else
123
+ html = ""
124
+ input_item = @template.radio_button_tag(name, opts)
125
+ end
126
+ html << "<label for='#{id}' class='#{klass}'>#{input_item}#{text}</label>"
127
+ end
128
+
129
+ def domize(text)
130
+ text.downcase.gsub(' ','_').gsub(/[^[:alnum:]]/, '')
131
+ end
132
+
133
+ def setup_label(attribute, type, options={})
134
+ marker = @@settings.label_required_marker
135
+ text = ""
136
+ text << marker if required?(attribute) && @@settings.label_required_marker_position == :prepend
137
+ text << field_human_name(attribute)
138
+ text << marker if required?(attribute) && @@settings.label_required_marker_position == :append
139
+ options.reverse_merge!(:caption => text, :class => css_class(attribute,type,options[:disabled]))
140
+ @template.label_tag(field_id(attribute), options)
141
+ end
142
+
143
+ def css_class(attribute,type,disabled=false)
144
+ klass = type.to_s
145
+ klass << ' required' if required?(attribute)
146
+ klass << ' required' if disabled
147
+ klass
148
+ end
149
+
150
+ def html_options(attribute,type,options)
151
+ options.keep_if {|key, value| key != :as}
152
+ html_class = options.merge(:class => css_class(attribute,type,options[:disabled]))
153
+ input_html = options[:input_html]
154
+ if input_html
155
+ html_class.merge(input_html) {|key, first, second| first + " " + second }.delete(:input_html)
156
+ else
157
+ html_class
158
+ end
159
+ end
160
+
161
+ def labelize(options)
162
+ opts = {}.merge(options)
163
+ opts.keep_if {|key, value| [:class,:id,:caption].include?(key)}
164
+ end
165
+
166
+ def hint(text)
167
+ @template.content_tag(:span, :class=>'hint') { text }
168
+ end
169
+
170
+ def default_radios(attribute,type,options)
171
+ [['yes',1],['no',0]].map do |item|
172
+ collection_input(attribute,:radios,item,options.keep_if {|key, value| key != :options})
173
+ end.join("")
174
+ end
175
+
176
+ def klazz
177
+ @object.class
178
+ end
179
+
180
+ end # StandardFormBuilder
181
+ end # FormBuilder
182
+ end # Helpers
183
+ end # Padrino
@@ -0,0 +1,63 @@
1
+ module Padrino
2
+ module Helpers
3
+ module FormHelpers
4
+
5
+ %w(date date email number search tel url).each do |type|
6
+ class_eval <<-EOF
7
+ ##
8
+ # Constructs a #{type} field input from the given options
9
+ #
10
+ # ==== Examples
11
+ #
12
+ # #{type}_field_tag :username, :class => 'long'
13
+ #
14
+ def #{type}_field_tag(name, options={})
15
+ options.reverse_merge!(:name => name)
16
+ input_tag(:#{type}, options)
17
+ end
18
+ EOF
19
+ end
20
+
21
+ def select_tag(name, options={})
22
+ options.reverse_merge!(:name => name)
23
+ collection, fields = options.delete(:collection), options.delete(:fields)
24
+ options[:options] = options_from_collection(collection, fields) if collection
25
+ prompt = options.delete(:include_blank)
26
+ select_options_html = if options[:options]
27
+ options_for_select(options.delete(:options), options.delete(:selected))
28
+ elsif options[:grouped_options]
29
+ grouped_options_for_select(options.delete(:grouped_options), options.delete(:selected), prompt)
30
+ end.unshift(blank_option(prompt))
31
+ options.merge!(:name => "#{options[:name]}[]") if options[:multiple]
32
+ content_tag(:select, select_options_html, options)
33
+ end
34
+
35
+ def grouped_options_for_select(collection,selected=nil,prompt=false)
36
+ if collection.is_a?(Hash)
37
+ collection.map do |key, value|
38
+ content_tag :optgroup, :label => key do
39
+ options_for_select(value, selected)
40
+ end
41
+ end
42
+ elsif collection.is_a?(Array)
43
+ collection.map do |optgroup|
44
+ content_tag :optgroup, :label => optgroup.first do
45
+ options_for_select(optgroup.last, selected)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def blank_option(prompt)
52
+ if prompt
53
+ case prompt.class.to_s
54
+ when 'String' ; content_tag(:option, prompt, :value => '') ;
55
+ when 'Array' ; content_tag(:option, prompt.first, :value => prompt.last) ;
56
+ else ; content_tag(:option, '', :value => '') ;
57
+ end
58
+ end
59
+ end
60
+
61
+ end # FormHelpers
62
+ end # Helpers
63
+ end # Padrino
@@ -0,0 +1,54 @@
1
+ require 'dm-core'
2
+ require 'dm-validations'
3
+
4
+ module PadrinoFields
5
+ module DataMapperWrapper
6
+ module ClassMethods
7
+
8
+ attr_reader :reflection
9
+
10
+ def form_attribute_validators; validators.contexts[:default]; end
11
+
12
+ def form_validators_on(attribute)
13
+ validators.contexts[:default].find_all {|v| v.field_name == attribute}
14
+ end
15
+
16
+ def form_attribute_is_required?(attribute)
17
+ form_validators_on(attribute).find_all {|v| v.class == DataMapper::Validations::PresenceValidator }.any?
18
+ end
19
+
20
+ def form_reflection_validators(reflection=nil)
21
+ new.send(reflection).validators.contexts[:default]
22
+ end
23
+
24
+ def form_has_required_attributes?(reflection=nil)
25
+ validators = form_attribute_validators
26
+ validators += reflection_validators(reflection) if reflection
27
+ validators.find_all {|v| v.class == DataMapper::Validations::PresenceValidator }.any?
28
+ end
29
+
30
+ def form_column_type_for(attribute)
31
+ klass = properties.find_all {|p| p.name == attribute}.first.class
32
+ if klass == DataMapper::Property::String
33
+ :string
34
+ elsif klass == DataMapper::Property::Text
35
+ :text
36
+ elsif [DataMapper::Property::Integer,DataMapper::Property::Decimal,DataMapper::Property::Float].include?(klass)
37
+ :number
38
+ elsif klass == DataMapper::Property::Boolean
39
+ :boolean
40
+ elsif [DataMapper::Property::Date,DataMapper::Property::DateTime].include?(klass)
41
+ :date
42
+ elsif klass == DataMapper::Property::Serial
43
+ :serial
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ end # ClassMethods
50
+ end # Datamapper
51
+ end # PadrinoFields
52
+
53
+ DataMapper::Model.append_extensions(PadrinoFields::DataMapperWrapper::ClassMethods)
54
+ #DataMapper::Model.append_inclusions(PadrinoFields::DataMapperWrapper::InstanceMethods)
@@ -0,0 +1,18 @@
1
+ module PadrinoFields
2
+ module Settings
3
+
4
+ mattr_accessor :container
5
+ @@container = :p
6
+
7
+ mattr_accessor :label_required_marker
8
+ @@label_required_marker = "<abbr>*</abbr>"
9
+
10
+ mattr_accessor :label_required_marker_position
11
+ @@label_required_marker_position = :prepend
12
+
13
+ def self.configure
14
+ yield self
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ begin
2
+ require File.expand_path('../.bundle/environment', __FILE__)
3
+ rescue LoadError
4
+ if defined?(Gem)
5
+ Gem.cache
6
+ gem 'bundler'
7
+ else
8
+ require 'rubygems'
9
+ end
10
+ require 'bundler'
11
+ Bundler.setup
12
+ end
@@ -0,0 +1,141 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{padrino-fields}
8
+ s.version = "0.3.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Steven Garcia"]
12
+ s.date = %q{2011-03-17}
13
+ s.description = %q{Smart fields for your forms, similar to Formtastic or SimpleForm}
14
+ s.email = %q{stevendgarcia@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.markdown",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/padrino-fields.rb",
28
+ "lib/padrino-fields/form_builder.rb",
29
+ "lib/padrino-fields/form_helpers.rb",
30
+ "lib/padrino-fields/orms/datamapper.rb",
31
+ "lib/padrino-fields/settings.rb",
32
+ "load_paths.rb",
33
+ "padrino-fields.gemspec",
34
+ "test/.DS_Store",
35
+ "test/fixtures/datamapper/app.rb",
36
+ "test/fixtures/datamapper/views/capture_concat.erb",
37
+ "test/fixtures/datamapper/views/capture_concat.haml",
38
+ "test/fixtures/datamapper/views/content_for.erb",
39
+ "test/fixtures/datamapper/views/content_for.haml",
40
+ "test/fixtures/datamapper/views/content_tag.erb",
41
+ "test/fixtures/datamapper/views/content_tag.haml",
42
+ "test/fixtures/datamapper/views/fields_for.erb",
43
+ "test/fixtures/datamapper/views/fields_for.haml",
44
+ "test/fixtures/datamapper/views/form_for.erb",
45
+ "test/fixtures/datamapper/views/form_for.haml",
46
+ "test/fixtures/datamapper/views/form_tag.erb",
47
+ "test/fixtures/datamapper/views/form_tag.haml",
48
+ "test/fixtures/datamapper/views/link_to.erb",
49
+ "test/fixtures/datamapper/views/link_to.haml",
50
+ "test/fixtures/datamapper/views/mail_to.erb",
51
+ "test/fixtures/datamapper/views/mail_to.haml",
52
+ "test/fixtures/datamapper/views/meta_tag.erb",
53
+ "test/fixtures/datamapper/views/meta_tag.haml",
54
+ "test/helper.rb",
55
+ "test/test_datamapper.rb",
56
+ "test/test_form_builder.rb",
57
+ "test/test_form_helpers.rb",
58
+ "test/test_settings.rb"
59
+ ]
60
+ s.homepage = %q{http://github.com/activestylus/padrino-fields}
61
+ s.licenses = ["MIT"]
62
+ s.require_paths = ["lib"]
63
+ s.rubygems_version = %q{1.3.7}
64
+ s.summary = %q{Advanced form helpers for Padrino framework}
65
+ s.test_files = [
66
+ "test/fixtures/datamapper/app.rb",
67
+ "test/helper.rb",
68
+ "test/test_datamapper.rb",
69
+ "test/test_form_builder.rb",
70
+ "test/test_form_helpers.rb",
71
+ "test/test_settings.rb"
72
+ ]
73
+
74
+ if s.respond_to? :specification_version then
75
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
76
+ s.specification_version = 3
77
+
78
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
79
+ s.add_runtime_dependency(%q<padrino>, [">= 0"])
80
+ s.add_runtime_dependency(%q<padrino-core>, [">= 0"])
81
+ s.add_runtime_dependency(%q<padrino-helpers>, [">= 0"])
82
+ s.add_development_dependency(%q<rcov>, [">= 0"])
83
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
84
+ s.add_development_dependency(%q<rake>, [">= 0.8.7"])
85
+ s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
86
+ s.add_development_dependency(%q<rack-test>, [">= 0.5.0"])
87
+ s.add_development_dependency(%q<fakeweb>, [">= 1.2.8"])
88
+ s.add_development_dependency(%q<webrat>, [">= 0.5.1"])
89
+ s.add_development_dependency(%q<haml>, [">= 2.2.22"])
90
+ s.add_development_dependency(%q<phocus>, [">= 0"])
91
+ s.add_development_dependency(%q<shoulda>, [">= 2.10.3"])
92
+ s.add_development_dependency(%q<uuid>, [">= 2.3.1"])
93
+ s.add_development_dependency(%q<bcrypt-ruby>, [">= 0"])
94
+ s.add_development_dependency(%q<ruby-prof>, [">= 0.9.1"])
95
+ s.add_development_dependency(%q<system_timer>, [">= 1.0"])
96
+ s.add_development_dependency(%q<memcached>, [">= 0.20.1"])
97
+ s.add_development_dependency(%q<dalli>, [">= 1.0.2"])
98
+ else
99
+ s.add_dependency(%q<padrino>, [">= 0"])
100
+ s.add_dependency(%q<padrino-core>, [">= 0"])
101
+ s.add_dependency(%q<padrino-helpers>, [">= 0"])
102
+ s.add_dependency(%q<rcov>, [">= 0"])
103
+ s.add_dependency(%q<jeweler>, [">= 0"])
104
+ s.add_dependency(%q<rake>, [">= 0.8.7"])
105
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
106
+ s.add_dependency(%q<rack-test>, [">= 0.5.0"])
107
+ s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
108
+ s.add_dependency(%q<webrat>, [">= 0.5.1"])
109
+ s.add_dependency(%q<haml>, [">= 2.2.22"])
110
+ s.add_dependency(%q<phocus>, [">= 0"])
111
+ s.add_dependency(%q<shoulda>, [">= 2.10.3"])
112
+ s.add_dependency(%q<uuid>, [">= 2.3.1"])
113
+ s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
114
+ s.add_dependency(%q<ruby-prof>, [">= 0.9.1"])
115
+ s.add_dependency(%q<system_timer>, [">= 1.0"])
116
+ s.add_dependency(%q<memcached>, [">= 0.20.1"])
117
+ s.add_dependency(%q<dalli>, [">= 1.0.2"])
118
+ end
119
+ else
120
+ s.add_dependency(%q<padrino>, [">= 0"])
121
+ s.add_dependency(%q<padrino-core>, [">= 0"])
122
+ s.add_dependency(%q<padrino-helpers>, [">= 0"])
123
+ s.add_dependency(%q<rcov>, [">= 0"])
124
+ s.add_dependency(%q<jeweler>, [">= 0"])
125
+ s.add_dependency(%q<rake>, [">= 0.8.7"])
126
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
127
+ s.add_dependency(%q<rack-test>, [">= 0.5.0"])
128
+ s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
129
+ s.add_dependency(%q<webrat>, [">= 0.5.1"])
130
+ s.add_dependency(%q<haml>, [">= 2.2.22"])
131
+ s.add_dependency(%q<phocus>, [">= 0"])
132
+ s.add_dependency(%q<shoulda>, [">= 2.10.3"])
133
+ s.add_dependency(%q<uuid>, [">= 2.3.1"])
134
+ s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
135
+ s.add_dependency(%q<ruby-prof>, [">= 0.9.1"])
136
+ s.add_dependency(%q<system_timer>, [">= 1.0"])
137
+ s.add_dependency(%q<memcached>, [">= 0.20.1"])
138
+ s.add_dependency(%q<dalli>, [">= 1.0.2"])
139
+ end
140
+ end
141
+