volt 0.8.26.beta1 → 0.8.26

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d71fdd9ba18f67e9349026c51395e553bb34143e
4
- data.tar.gz: 00ac6d296fb6a2e32d7d8326740e378ea5178545
3
+ metadata.gz: 47aaf2be39754e3e1e663f8f30be5ca0b5185980
4
+ data.tar.gz: 4a3efe149301a81d2cf06ba98f354bf0accad0e4
5
5
  SHA512:
6
- metadata.gz: 774f656f5a4c365d9f37106a0204efcff36b2b72871d7f4b3bd5334b75f16ec3195b82cdecc5f23781efd76f896d130ae205a5e3f0691bd01888778cc567f12a
7
- data.tar.gz: c50312a4099bd67fcc60684fca2353b0929c0878cce00e61bef809257ee3613e14796369ea47f18755d24aea59d648da28de32a4974c21a6b70b064079c80cba
6
+ metadata.gz: b8095761ae07bc9aa0ff5619fec850defa145a926593b78bee12305de2b8d8d7db8f4c0d91d6093a5b5dd4ad3d59475c20d0ce6e73945e6bc73deca48a25d8a4
7
+ data.tar.gz: 327aee6d016ac99b70e8facefe3eb04795d6a8ff6c11f5145796e31711f9b712f7a04d294b5d4f260b89f2cc0105a7c3307b6ce9b5a00ea5557ec926565809d9
data/CHANGELOG.md CHANGED
@@ -1,13 +1,8 @@
1
1
  # Change Log
2
2
 
3
- ## 0.8.25 - ...
4
- ### Added
5
- - Added email validator
6
- - each_with_index is now supported in views and the ```index``` value is no longer provided by default.
7
3
 
8
4
 
9
5
  ## 0.8.24 - 2014-12-05
10
- ### Added
11
6
  - Fix bug with validation inheritance
12
7
  - Fixed issue with controller loading.
13
8
 
data/Rakefile CHANGED
@@ -1,7 +1,8 @@
1
1
  require 'bundler'
2
2
  require 'bundler/gem_tasks'
3
- Bundler.require(:development)
4
3
  require 'rubocop/rake_task'
4
+ Bundler.require(:development)
5
+
5
6
  require 'opal'
6
7
 
7
8
  # Add our opal/ directory to the load path
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.26.beta1
1
+ 0.8.26
@@ -12,7 +12,6 @@ module Volt
12
12
  end
13
13
 
14
14
  validate login_field, unique: true, length: 8
15
- validate :email, email: true
16
15
 
17
16
  if RUBY_PLATFORM == 'opal'
18
17
  # Don't validate on the server
@@ -0,0 +1,28 @@
1
+ # Getting Started
2
+
3
+ Volt relies on a few concepts to take make web development faster and easier. The first of these is reactive programming. Data on the front and back end is stored in models. Instead of manually updating a page when the data changes, the page is coded using a templating language which automatically updates when the data changes.
4
+
5
+ ## Bindings and Models
6
+
7
+ This automaic updating is done via bindings and models. In Volt app's all data is stored in a model. From your html, you can bind things like attributes and text to a value in a model.
8
+
9
+ ### Name Example
10
+
11
+ ```html
12
+ <label>Name:</label>
13
+ <input type="text" value="{page._name}" />
14
+ <p>Hello {page._name}</p>
15
+ ```
16
+
17
+ In the example above, our model is called page (more about page later). Any time a user changes the value of the field, page._name will be updated to the fields value. When page._name is changed, the fields value changes. Also when ```page._name``` changes, the page will show the text "Hello ..." where ... is the value of page._name. These "two-way bindings" help us eliminiate a lot of code by keeping all of our application state in our models. Data displayed in a view is always computed live from the data in the models.
18
+
19
+ ### Meal Cost Splitter Example
20
+
21
+ ```html
22
+ <label>Cost:</label><input type="text" value="{page._cost}" /><br />
23
+ <label>People:</label><input type="text" value="{page._people}" /><br />
24
+ <p>Cost Per Person: {page._cost.to_f / page._people.to_f}</p>
25
+ ```
26
+ In this example, a user can enter a cost and a number of people. When either changes, the Cost Per Person will update.
27
+
28
+ ###
@@ -0,0 +1,2 @@
1
+ # Integrating JavaScript
2
+
data/docs/WHY.md ADDED
@@ -0,0 +1,39 @@
1
+ # Why Volt?
2
+
3
+ Volt is a new web framework. You use Ruby for both your client and server code. Volt helps you break your code into reusable components. It handles managing all assets and dependencies for you. Volt automatically updates your pages for you when your model data changes and sync's that data to the database for you. By providing reusable structure and handling common tasks, Volt lets you build web app's really fast!
4
+
5
+ # Features
6
+
7
+ ## Components
8
+
9
+ Volt projects are broken into components. Components are easy to create and simple to reuse. They are easily shared and only require one line of code to insert into your project. Volt provides many common components out of the box.
10
+
11
+ ## Reactive
12
+
13
+ Data in volt is reactive by default. Changes to the data is automatically updated in the DOM.
14
+
15
+
16
+ ## Data Syncing
17
+
18
+ A lot of modern web development is moving data between the front-end to the back-end. Volt eliminates all of that work. Model's on the front-end automatically sync to the back-end, and vice versa. Validations are run on both sides for security. Models on the front-end are automatically updated whenever they are changed anywhere else (another browser, a background task, etc..)
19
+
20
+
21
+ # Why Volt is Awesome
22
+
23
+ - only the relevant DOM is updated. There is no match and patch algorithm to update from strings like other frameworks, all associations are tracked through our reactive core, so we know exactly what needs to be updated without the need to generate any extra HTML. This has a few advantages, namely that things like input fields are retained, so any properties (focus, tab position, etc...) are also retained.
24
+
25
+
26
+ # Why Ruby
27
+
28
+ Isomorphic type system with javascript
29
+
30
+ In web development today, JavaScript gets to be the default language by virtue of being in the browser. JavaScript is a very good language, but it has a lot of warts. (See http://wtfjs.com/ for some great examples) Some of these can introduce bugs, others are just difficult to deal with. JavaScript was rushed to market quickly and standardized very quickly. Ruby was used by a small community for years while most of the kinks were worked out. Ruby also has some great concepts such as [uniform access](http://en.wikipedia.org/wiki/Uniform_access_principle), [mixin's](http://en.wikipedia.org/wiki/Mixin), [duck typing](http://en.wikipedia.org/wiki/Duck_typing), and [blocks](http://yehudakatz.com/2012/01/10/javascript-needs-blocks/) to name a few. While many of these features can be implemented in JavaScript in userland, few are standardardized and the solutions are seldom eloquent.
31
+
32
+ [5,10,1].sort()
33
+ // [1, 10, 5]
34
+
35
+ Uniform access and duck typing provides us with the ability to make reactive objects that have the exact same interface as a normal object. This is a big win, nothing new to learn to do reactive programming. They can also be used interchangably with regular objects.
36
+
37
+ # Why Opal
38
+
39
+ Opal is really an increadiable project, and the core team has done a great job. Ruby and JavaScript are similar in a lot of ways. This lets Opal compile to JavaScript that is very readable. This also means that Opal's performance is great. You'll find that in most cases Ruby code runs with no performance penality compared to the eqivilent JavaScript code.
data/lib/volt/cli.rb CHANGED
@@ -32,8 +32,7 @@ module Volt
32
32
  end
33
33
 
34
34
  desc 'server', 'run the server on the project in the current directory'
35
- method_option :port, type: :string, aliases: '-p', banner: 'the port the server should run on'
36
- method_option :bind, type: :string, aliases: '-b', banner: 'the ip the server should bind to'
35
+ method_option :port, type: :string, aliases: '-p', banner: 'specify which port the server should run on'
37
36
 
38
37
  def server
39
38
  if RUBY_PLATFORM == 'java'
@@ -62,8 +61,9 @@ module Volt
62
61
  ENV['SERVER'] = 'true'
63
62
  args = ['start', '--threaded', '--max-persistent-conns', '300']
64
63
  args += ['--max-conns', '400'] unless Gem.win_platform?
65
- args += ['-p', options[:port].to_s] if options[:port]
66
- args += ['-b', options[:bind].to_s] if options[:bind]
64
+ if options[:port]
65
+ args += ['-p', options[:port].to_s]
66
+ end
67
67
 
68
68
  Thin::Runner.new(args).run!
69
69
  end
@@ -1,10 +1,8 @@
1
1
  # require 'volt/models/validations/errors'
2
- require 'volt/models/validators/email_validator'
3
2
  require 'volt/models/validators/length_validator'
4
- require 'volt/models/validators/numericality_validator'
5
- require 'volt/models/validators/phone_number_validator'
6
3
  require 'volt/models/validators/presence_validator'
7
4
  require 'volt/models/validators/unique_validator'
5
+ require 'volt/models/validators/numericality_validator'
8
6
 
9
7
  module Volt
10
8
  # Include in any class to get validation logic
@@ -2,11 +2,10 @@ require 'volt/page/bindings/base_binding'
2
2
 
3
3
  module Volt
4
4
  class EachBinding < BaseBinding
5
- def initialize(page, target, context, binding_name, getter, variable_name, index_name, template_name)
5
+ def initialize(page, target, context, binding_name, getter, variable_name, template_name)
6
6
  super(page, target, context, binding_name)
7
7
 
8
8
  @item_name = variable_name
9
- @index_name = index_name
10
9
  @template_name = template_name
11
10
 
12
11
  @templates = []
@@ -29,6 +28,7 @@ module Volt
29
28
  # Since we're checking things like size, we don't want this to be re-triggered on a
30
29
  # size change, so we run without tracking.
31
30
  Computation.run_without_tracking do
31
+ # puts "RELOAD:-------------- #{value.inspect}"
32
32
  # Adjust to the new size
33
33
  values = current_values(value)
34
34
  @value = values
@@ -56,8 +56,9 @@ module Volt
56
56
 
57
57
  def item_removed(position)
58
58
  # Remove dependency
59
- @templates[position].context.locals[:_index_dependency].remove
59
+ @templates[position].context.locals[:index_dependency].remove
60
60
 
61
+ # puts "REMOVE AT: #{position.inspect} - #{@templates[position].inspect} - #{@templates.inspect}"
61
62
  @templates[position].remove_anchors
62
63
  @templates[position].remove
63
64
  @templates.delete_at(position)
@@ -83,21 +84,17 @@ module Volt
83
84
  item_context.locals[@item_name.to_sym] = proc { @value[item_context.locals[:_index_value]]}
84
85
 
85
86
  position_dependency = Dependency.new
86
- item_context.locals[:_index_dependency] = position_dependency
87
+ item_context.locals[:index_dependency] = position_dependency
87
88
 
88
89
  # Get and set index
89
- item_context.locals[:_index=] = proc do |val|
90
+ item_context.locals[:index=] = proc do |val|
90
91
  position_dependency.changed!
91
92
  item_context.locals[:_index_value] = val
92
93
  end
93
94
 
94
- # If the user provides an each_with_index, we can assign the lookup for the index
95
- # variable here.
96
- if @index_name
97
- item_context.locals[@index_name.to_sym] = proc do
98
- position_dependency.depend
99
- item_context.locals[:_index_value]
100
- end
95
+ item_context.locals[:index] = proc do
96
+ position_dependency.depend
97
+ item_context.locals[:_index_value]
101
98
  end
102
99
 
103
100
  item_template = TemplateRenderer.new(@page, @target, item_context, binding_name, @template_name)
@@ -112,7 +109,7 @@ module Volt
112
109
  size = @templates.size
113
110
  if size > 0
114
111
  start_index.upto(size - 1) do |index|
115
- @templates[index].context.locals[:_index=].call(index)
112
+ @templates[index].context.locals[:index=].call(index)
116
113
  end
117
114
  end
118
115
  end
@@ -1,6 +1,6 @@
1
1
  module Volt
2
2
  # The tasks class provides an interface to call tasks on
3
- # the backend server. This class is setup as page.task (as a singleton)
3
+ # the backend server.
4
4
  class Tasks
5
5
  def initialize(page)
6
6
  @page = page
@@ -21,6 +21,7 @@ module Volt
21
21
  @promises[promise_id] = promise
22
22
 
23
23
  # TODO: Timeout on these callbacks
24
+
24
25
  @page.channel.send_message([promise_id, class_name, method_name, meta_data, *args])
25
26
 
26
27
  promise
@@ -1,15 +1,12 @@
1
1
  module Volt
2
2
  class EachScope < ViewScope
3
- def initialize(handler, path, content, with_index)
3
+ def initialize(handler, path, content)
4
4
  super(handler, path)
5
+ # @content, @variable_name = content.strip.split(/ as /)
5
6
 
6
- if with_index
7
- @content, @variable_name = content.split(/.each_with_index\s+do\s+\|/)
8
- @variable_name, @index_name = @variable_name.gsub(/\|/, '').split(/\s*,\s*/)
9
- else
10
- @content, @variable_name = content.split(/.each\s+do\s+\|/)
11
- @variable_name = @variable_name.gsub(/\|/, '')
12
- end
7
+ @content, @variable_name = content.split(/.each\s+do\s+\|/)
8
+
9
+ @variable_name = @variable_name.gsub(/\|/, '')
13
10
  end
14
11
 
15
12
  def close_scope
@@ -20,7 +17,7 @@ module Volt
20
17
  super
21
18
 
22
19
  @handler.html << "<!-- $#{binding_number} --><!-- $/#{binding_number} -->"
23
- @handler.scope.last.save_binding(binding_number, "lambda { |__p, __t, __c, __id| Volt::EachBinding.new(__p, __t, __c, __id, Proc.new { #{@content} }, #{@variable_name.inspect}, #{@index_name.inspect}, #{@path.inspect}) }")
20
+ @handler.scope.last.save_binding(binding_number, "lambda { |__p, __t, __c, __id| Volt::EachBinding.new(__p, __t, __c, __id, Proc.new { #{@content} }, #{@variable_name.inspect}, #{@path.inspect}) }")
24
21
  end
25
22
  end
26
23
  end
@@ -42,9 +42,7 @@ module Volt
42
42
  add_template(args)
43
43
  else
44
44
  if content =~ /.each\s+do\s+\|/
45
- add_each(content, false)
46
- elsif content =~ /.each_with_index\s+do\s+\|/
47
- add_each(content, true)
45
+ add_each(content)
48
46
  else
49
47
  add_content_binding(content)
50
48
  end
@@ -78,8 +76,8 @@ module Volt
78
76
  fail '#else can only be added inside of an if block'
79
77
  end
80
78
 
81
- def add_each(content, with_index)
82
- @handler.scope << EachScope.new(@handler, @path + "/__each#{@binding_number}", content, with_index)
79
+ def add_each(content)
80
+ @handler.scope << EachScope.new(@handler, @path + "/__each#{@binding_number}", content)
83
81
  end
84
82
 
85
83
  def add_template(content)
@@ -7,9 +7,8 @@
7
7
  <div id="count">{{ completed }} of {{ _todos.size }}</div>
8
8
 
9
9
  <table id="todos-table" class="table">
10
- {{ _todos.each_with_index do |todo, idx| }}
10
+ {{ _todos.each do |todo| }}
11
11
  <tr>
12
- <td>{{ idx+1 }}.</td>
13
12
  <td><input type="checkbox" checked="{{ todo._completed }}"></td>
14
13
  <td class="name {{ if todo._completed }}complete{{ end }}">{{todo._name}}</td>
15
14
  <td><button e-click="remove_todo(todo)">X</button></td>
@@ -1,23 +1,19 @@
1
- require 'spec_helper'
1
+ require 'volt/models'
2
2
 
3
3
  class TestModel < Volt::Model
4
- validate :count, numericality: { min: 5, max: 10 }
5
- validate :description, length: { message: 'needs to be longer', length: 50 }
6
- validate :email, email: true
7
4
  validate :name, length: 4
8
- validate :phone_number, phone_number: true
5
+ validate :description, length: { message: 'needs to be longer', length: 50 }
9
6
  validate :username, presence: true
7
+ validate :count, numericality: { min: 5, max: 10 }
10
8
  end
11
9
 
12
10
  describe Volt::Model do
13
11
  it 'should validate the name' do
14
12
  expect(TestModel.new.errors).to eq(
15
- count: ['must be a number'],
16
- description: ['needs to be longer'],
17
- email: ['must be an email address'],
18
13
  name: ['must be at least 4 characters'],
19
- phone_number: ['must be a phone number with area or country code'],
20
- username: ['must be specified']
14
+ description: ['needs to be longer'],
15
+ username: ['must be specified'],
16
+ count: ['must be a number']
21
17
  )
22
18
  end
23
19
 
@@ -40,9 +36,7 @@ describe Volt::Model do
40
36
 
41
37
  model.save!
42
38
 
43
- expect(model.marked_errors.keys).to eq(
44
- [:count, :description, :email, :name, :phone_number, :username]
45
- )
39
+ expect(model.marked_errors.keys).to eq([:name, :description, :username, :count])
46
40
  end
47
41
 
48
42
  describe 'length' do
@@ -87,31 +81,4 @@ describe Volt::Model do
87
81
  end
88
82
  end
89
83
 
90
- describe 'email' do
91
- it 'should validate email' do
92
- model = TestModel.new
93
-
94
- expect(model.marked_errors).to eq({})
95
-
96
- model.mark_field!(:email)
97
-
98
- expect(model.marked_errors).to eq(
99
- email: ['must be an email address']
100
- )
101
- end
102
- end
103
-
104
- describe 'phone_number' do
105
- it 'should validate phone number' do
106
- model = TestModel.new
107
-
108
- expect(model.marked_errors).to eq({})
109
-
110
- model.mark_field!(:phone_number)
111
-
112
- expect(model.marked_errors).to eq(
113
- phone_number: ['must be a phone number with area or country code']
114
- )
115
- end
116
- end
117
84
  end
@@ -117,7 +117,7 @@ describe Volt::ViewParser do
117
117
  'html' => " <div class=\"main\">\n <!-- $0 --><!-- $/0 -->\n </div>\n",
118
118
  'bindings' => {
119
119
  0 => [
120
- "lambda { |__p, __t, __c, __id| Volt::EachBinding.new(__p, __t, __c, __id, Proc.new { _items }, \"item\", nil, \"main/main/main/body/__each0/__template/0\") }"
120
+ "lambda { |__p, __t, __c, __id| Volt::EachBinding.new(__p, __t, __c, __id, Proc.new { _items }, \"item\", \"main/main/main/body/__each0/__template/0\") }"
121
121
  ]
122
122
  }
123
123
  })
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: volt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.26.beta1
4
+ version: 0.8.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Stout
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-19 00:00:00.000000000 Z
11
+ date: 2014-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -453,6 +453,9 @@ files:
453
453
  - app/volt/views/notices/index.html
454
454
  - bin/volt
455
455
  - docs/FAQ.md
456
+ - docs/GETTING_STARTED.md
457
+ - docs/JAVASCRIPT_COMPONENTS.md
458
+ - docs/WHY.md
456
459
  - docs/volt-logo.jpg
457
460
  - lib/volt.rb
458
461
  - lib/volt/assets/test.rb
@@ -508,10 +511,8 @@ files:
508
511
  - lib/volt/models/persistors/store_state.rb
509
512
  - lib/volt/models/url.rb
510
513
  - lib/volt/models/validations.rb
511
- - lib/volt/models/validators/email_validator.rb
512
514
  - lib/volt/models/validators/length_validator.rb
513
515
  - lib/volt/models/validators/numericality_validator.rb
514
- - lib/volt/models/validators/phone_number_validator.rb
515
516
  - lib/volt/models/validators/presence_validator.rb
516
517
  - lib/volt/models/validators/unique_validator.rb
517
518
  - lib/volt/page/bindings/attribute_binding.rb
@@ -630,8 +631,6 @@ files:
630
631
  - spec/models/persistors/params_spec.rb
631
632
  - spec/models/persistors/store_spec.rb
632
633
  - spec/models/validations_spec.rb
633
- - spec/models/validators/email_validator_spec.rb
634
- - spec/models/validators/phone_number_validator_spec.rb
635
634
  - spec/page/bindings/content_binding_spec.rb
636
635
  - spec/page/bindings/template_binding_spec.rb
637
636
  - spec/page/sub_context_spec.rb
@@ -724,9 +723,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
724
723
  version: '0'
725
724
  required_rubygems_version: !ruby/object:Gem::Requirement
726
725
  requirements:
727
- - - ">"
726
+ - - ">="
728
727
  - !ruby/object:Gem::Version
729
- version: 1.3.1
728
+ version: '0'
730
729
  requirements: []
731
730
  rubyforge_project:
732
731
  rubygems_version: 2.2.2
@@ -780,8 +779,6 @@ test_files:
780
779
  - spec/models/persistors/params_spec.rb
781
780
  - spec/models/persistors/store_spec.rb
782
781
  - spec/models/validations_spec.rb
783
- - spec/models/validators/email_validator_spec.rb
784
- - spec/models/validators/phone_number_validator_spec.rb
785
782
  - spec/page/bindings/content_binding_spec.rb
786
783
  - spec/page/bindings/template_binding_spec.rb
787
784
  - spec/page/sub_context_spec.rb
@@ -1,40 +0,0 @@
1
- module Volt
2
- class EmailValidator
3
- DEFAULT_REGEX = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
4
- ERROR_MESSAGE = 'must be an email address'
5
-
6
- def self.validate(model, old_model, field_name, options)
7
- new(model, field_name, options).errors
8
- end
9
-
10
- def initialize(model, field_name, options)
11
- @value = model.read_attribute field_name
12
-
13
- case options
14
- when Hash, true, false
15
- configure options
16
- else
17
- fail 'arguments can only be a Boolean or a Hash'
18
- end
19
- end
20
-
21
- def valid?
22
- return false unless @value.is_a? String
23
-
24
- !!@value.match(@custom_regex || DEFAULT_REGEX)
25
- end
26
-
27
- def errors
28
- valid? ? {} : { email: [ @custom_message || ERROR_MESSAGE ] }
29
- end
30
-
31
- private
32
-
33
- def configure(options)
34
- return unless options.is_a? Hash
35
-
36
- @custom_message = options.fetch(:error_message) { nil }
37
- @custom_regex = options.fetch(:with) { nil }
38
- end
39
- end
40
- end
@@ -1,40 +0,0 @@
1
- module Volt
2
- class PhoneNumberValidator
3
- DEFAULT_REGEX = /^(\+?\d{1,2}[\.\-\ ]?\d{3}|\(\d{3}\)|\d{3})[\.\-\ ]?\d{3,4}[\.\-\ ]?\d{4}$/
4
- ERROR_MESSAGE = 'must be a phone number with area or country code'
5
-
6
- def self.validate(model, old_model, field_name, options)
7
- new(model, field_name, options).errors
8
- end
9
-
10
- def initialize(model, field_name, options)
11
- @value = model.read_attribute field_name
12
-
13
- case options
14
- when Hash, true, false
15
- configure options
16
- else
17
- fail 'arguments can only be a Boolean or a Hash'
18
- end
19
- end
20
-
21
- def valid?
22
- return false unless @value.is_a? String
23
-
24
- !!@value.match(@custom_regex || DEFAULT_REGEX)
25
- end
26
-
27
- def errors
28
- valid? ? {} : { phone_number: [ @custom_message || ERROR_MESSAGE ] }
29
- end
30
-
31
- private
32
-
33
- def configure(options)
34
- return unless options.is_a? Hash
35
-
36
- @custom_message = options.fetch(:error_message) { nil }
37
- @custom_regex = options.fetch(:with) { nil }
38
- end
39
- end
40
- end
@@ -1,120 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Volt::EmailValidator do
4
- subject { Volt::EmailValidator.new(*params) }
5
- let(:params) { [ model, field_name, options ] }
6
-
7
- let(:model) { Volt::Model.new email: email }
8
- let(:field_name) { :email }
9
- let(:options) { true }
10
-
11
- let(:valid_email) { 'test@example.com' }
12
- let(:invalid_email) { 'test@example-com' }
13
- let(:email) { valid_email }
14
-
15
- describe '.validate' do
16
- let(:result) { described_class.validate(*params.dup.insert(1, nil)) }
17
-
18
- before do
19
- allow(described_class).to receive(:new).and_return subject
20
- allow(subject).to receive(:errors).and_call_original
21
-
22
- result
23
- end
24
-
25
- it 'initializes an email validator with the provided arguments' do
26
- expect(described_class).to have_received(:new).with(*params)
27
- end
28
-
29
- it 'calls errors on the email validator' do
30
- expect(subject).to have_received :errors
31
- end
32
-
33
- it 'returns the result of calling errors on the validator' do
34
- expect(subject.errors).to eq result
35
- end
36
- end
37
-
38
- describe '#valid?' do
39
- context 'when using the default regex' do
40
- let(:options) { true }
41
-
42
- context 'when the email is valid' do
43
- let(:email) { valid_email }
44
-
45
- specify { expect(subject.valid?).to eq true }
46
- end
47
-
48
- context 'when the email is missing a TLD' do
49
- let(:email) { 'test@example' }
50
-
51
- specify { expect(subject.valid?).to eq false }
52
- end
53
-
54
- context 'when the email TLD is only one character' do
55
- let(:email) { 'test@example.c' }
56
-
57
- specify { expect(subject.valid?).to eq false }
58
- end
59
-
60
- context 'when the email is missing an username' do
61
- let(:email) { '@example.com' }
62
-
63
- specify { expect(subject.valid?).to eq false }
64
- end
65
-
66
- context 'when the email is missing the @ symbol' do
67
- let(:email) { 'test.example.com' }
68
-
69
- specify { expect(subject.valid?).to eq false }
70
- end
71
- end
72
-
73
- context 'when using a custom regex' do
74
- let(:options) { { with: /.+\@.+/ } }
75
-
76
- context 'and the email qualifies' do
77
- let(:email) { 'test@example' }
78
-
79
- specify { expect(subject.valid?).to eq true }
80
- end
81
-
82
- context 'and the email does not qualify' do
83
- let(:email) { 'test$example' }
84
-
85
- specify { expect(subject.valid?).to eq false }
86
- end
87
- end
88
- end
89
-
90
- describe '#errors' do
91
- context 'when the model has a valid email' do
92
- let(:email) { valid_email }
93
-
94
- it 'returns an empty error hash' do
95
- expect(subject.errors).to eq({})
96
- end
97
- end
98
-
99
- context 'when the model has an invalid email' do
100
- let(:email) { invalid_email }
101
-
102
- it 'returns an array of errors for email' do
103
- expect(subject.errors).to eq(email: ['must be an email address'])
104
- end
105
- end
106
-
107
- context 'when provided a custom error message' do
108
- let(:options) { { error_message: custom_message } }
109
- let(:custom_message) { 'this is a custom message' }
110
-
111
- context 'and the email is invalid' do
112
- let(:email) { invalid_email }
113
-
114
- it 'returns errors with the custom message' do
115
- expect(subject.errors).to eq(email: [ custom_message ])
116
- end
117
- end
118
- end
119
- end
120
- end
@@ -1,146 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Volt::PhoneNumberValidator do
4
- subject { Volt::PhoneNumberValidator.new(*params) }
5
- let(:params) { [ model, field_name, options ] }
6
-
7
- let(:model) { Volt::Model.new phone_number: phone_number }
8
- let(:field_name) { :phone_number }
9
- let(:options) { true }
10
-
11
- let(:valid_us_number) { '(123)-123-1234' }
12
- let(:valid_intl_number) { '+12 123 123 1234' }
13
- let(:invalid_number) { '1234-123-123456' }
14
- let(:phone_number) { valid_us_number }
15
-
16
- describe '.validate' do
17
- let(:result) { described_class.validate(*params.dup.insert(1, nil)) }
18
-
19
- before do
20
- allow(described_class).to receive(:new).and_return subject
21
- allow(subject).to receive(:errors).and_call_original
22
-
23
- result
24
- end
25
-
26
- it 'initializes a phone number validator with the provided arguments' do
27
- expect(described_class).to have_received(:new).with(*params)
28
- end
29
-
30
- it 'calls errors on the phone number validator' do
31
- expect(subject).to have_received :errors
32
- end
33
-
34
- it 'returns the result of calling errors on the validator' do
35
- expect(subject.errors).to eq result
36
- end
37
- end
38
-
39
- describe '#valid?' do
40
- context 'when using the default regex' do
41
- let(:options) { true }
42
-
43
- context 'when the phone number is a valid US number' do
44
- let(:phone_number) { valid_us_number }
45
-
46
- specify { expect(subject.valid?).to eq true }
47
- end
48
-
49
- context 'when the phone number is a valid international number' do
50
- let(:phone_number) { valid_intl_number }
51
-
52
- specify { expect(subject.valid?).to eq true }
53
- end
54
-
55
- context 'when the phone number uses dashes' do
56
- let(:phone_number) { '123-123-1234' }
57
-
58
- specify { expect(subject.valid?).to eq true }
59
- end
60
-
61
- context 'when the phone number uses periods' do
62
- let(:phone_number) { '123.123.1234' }
63
-
64
- specify { expect(subject.valid?).to eq true }
65
- end
66
-
67
- context 'when the phone number uses spaces' do
68
- let(:phone_number) { '123 123 1234' }
69
-
70
- specify { expect(subject.valid?).to eq true }
71
- end
72
-
73
- context 'when the phone number uses parentheses and a space' do
74
- let(:phone_number) { '(123) 123.1234' }
75
-
76
- specify { expect(subject.valid?).to eq true }
77
- end
78
-
79
- context 'when an international number uses a plus' do
80
- let(:phone_number) { '+12 123 123 1234' }
81
-
82
- specify { expect(subject.valid?).to eq true }
83
- end
84
-
85
- context 'when an international number does not use a plus' do
86
- let(:phone_number) { '12 123 123 1234' }
87
-
88
- specify { expect(subject.valid?).to eq true }
89
- end
90
-
91
- context 'when an international number is from the UK' do
92
- let(:phone_number) { '+12 123 1234 1234' }
93
-
94
- specify { expect(subject.valid?).to eq true }
95
- end
96
- end
97
-
98
- context 'when using a custom regex' do
99
- let(:options) { { with: /\d{10}/ } }
100
-
101
- context 'and the phone number qualifies' do
102
- let(:phone_number) { '1231231234' }
103
-
104
- specify { expect(subject.valid?).to eq true }
105
- end
106
-
107
- context 'and the phone number does not qualify' do
108
- let(:phone_number) { '123-123-1234' }
109
-
110
- specify { expect(subject.valid?).to eq false }
111
- end
112
- end
113
- end
114
-
115
- describe '#errors' do
116
- context 'when the model has a valid phone number' do
117
- let(:phone_number) { valid_us_number }
118
-
119
- it 'returns an empty error hash' do
120
- expect(subject.errors).to eq({})
121
- end
122
- end
123
-
124
- context 'when the model has an invalid phone number' do
125
- let(:phone_number) { invalid_number }
126
-
127
- it 'returns an array of errors for phone number' do
128
- expect(subject.errors).to eq(
129
- phone_number: ['must be a phone number with area or country code'])
130
- end
131
- end
132
-
133
- context 'when provided a custom error message' do
134
- let(:options) { { error_message: custom_message } }
135
- let(:custom_message) { 'this is a custom message' }
136
-
137
- context 'and the phone number is invalid' do
138
- let(:phone_number) { invalid_number }
139
-
140
- it 'returns errors with the custom message' do
141
- expect(subject.errors).to eq(phone_number: [ custom_message ])
142
- end
143
- end
144
- end
145
- end
146
- end