When I try to validate for data types in Malli, what is the difference between using : and ? in Malli?
Like when I try for float, it fails for :float as invalid schema. But we are allowed to use :int and :string right? So why does it fail for :float?
And why does it work for float?
Here is an example :
(m/validate :float 788.89)
Execution error (ExceptionInfo) at malli.core/-fail! (core.cljc:138).
:malli.core/invalid-schema {:schema :float}
(m/validate float? 788.89)
=> true
How does this work?
(m/validate :int 788)
=> true
(m/validate int? 788)
=> true
(m/validate string? "89")
=> true
(m/validate :string "89")
=> true
(m/validate string? 89)
=> false
Malli by default does not know anything about :float. What's available is in malli.core/predicate-schemas.
If you want to use :float, you have to use custom registry.
Related
I have a string which is passed as a parameter to a function. Here, I want to check if the string contains only numbers. So I had a check like below:
def check_string(string)
result = false
if string.to_i.to_s.eql? string
result = true
end
result
end
But the problem arises when a string starts with 0. In that case, a false is returned.
check_string('123') #=> true
check_string('0123') #=> false
How can I solve this issue?
You can try the following
def check_string(string)
string.scan(/\D/).empty?
end
It would be truthy if string contains only digits or if it is an empty string. Otherwise returns false.
A number can be negative, or a float. So if these are allowed, consider this solution:
def is_numberic?(str)
str == "#{str.to_f}" || str == "#{str.to_i}"
end
some input which evaluate to true
pry(main)> is_numberic? '5'
=> true
pry(main)> is_numberic? '58127721'
=> true
pry(main)> is_numberic? '58127721.737673'
=> true
pry(main)> is_numberic? '0'
=> true
pry(main)> is_numberic? '1818'
=> true
pry(main)> is_numberic? '0.1'
=> true
pry(main)> is_numberic? '0.0'
=> true
pry(main)> is_numberic? '11.29'
=> true
pry(main)> is_numberic? '-0.12'
=> true
pry(main)> is_numberic? '-29'
=> true
the input which evaluate to false
pry(main)> is_numberic? '10 years'
=> false
pry(main)> is_numberic? '01'
=> false
pry(main)> is_numberic? '00'
=> false
pry(main)> is_numberic? '0.10'
=> false
pry(main)> is_numberic? ''
=> false
As you can see, there're several cases which probably should be supported, eg '0.10', but are not. In this case, the permitted input is '0.1'.
def check_string(str)
str !~ /\D/
end
check_string '123'
#=> true
check_string ''
#=> true
check_string '1a2'
#=> false
this is my proposition for detecting if it's a float number
def check(string)
scan = string.scan(/\D/)
scan.size == 0 || (scan.size == 1 && scan.first == ".") # or "," depend on your separator
end
example of use:
check("123") => true
check("12.3") => true
check("12e3") => false
check("12.3.2") => false
EDIT: 2023
After some years i see this is the most compact solution:
def check_string(str)
str.scan(/\D/).empty?
end
You can use Regexp for it:
def check_string(string)
raise 'Empty string passed' if string.empty?
/\A\d+\z/ === string
end
check_string '123'
#=> true
check_string '0123'
#=> true
check_string '0'
#=> true
We can also use the "match" function to do this.
"1234".match(/\D/)
#=> nil
"1234foo".match(/\D/)
#=> #<MatchData "f">
match (String) - APIdock
I think we should use the regex to find this.
it will work for the below scenarios
"3.0"
"av3"
"3"
is_numeric = false if option.option.match?(/[^0-9.]/)
If anyone is searching for another way to determine if string is numeric -> is to use "is_a? Numeric". Is_a? reference documentation
"namaste".is_a? Numeric
=> false
6.is_a? Numeric
=> true
str1 = "foo"
str2 = 9
str1.is_a? Numeric
=> false
str2.is_a? Numeric
=> true
You can also use:
7.is_a?(Numeric)
=> true
"too".is_a?(Numeric)
=> false
Basically it's determining if a class is a type of class object. I just found this and thought I would share.
This is my code:
fred = {
'age' => 63,
'gender' => 'male',
'favorite painters' => ['Monet', 'Constable', 'Da Vinci']
}
fred.delete_if { |k,v| k.match(/[a]/) }
puts fred
The result shows {"gender"=>"male"}.
If I change the code to
fred.delete_if { |k,v| k.include?(/[a]/) }
it won't work.
Can anyone explain why to me?
String#match takes a regex object (or a regex pattern string) as the parameter while String#included? takes a string as the parameter.
You should use:
fred.delete_if { |k,v| k.include?('a') }
For more info, see the document.
.include? returns boolean true/false, and expects a string as input.
.match returns information about the match in the form of MatchData (or nil if nothing was matched), and accepts a string or regular expression.
Everyone is recommending using include? for a literal match. I prefer a different syntax that accomplishes the same thing:
"foo".include?("o") # => true
"foo"["o"] # => "o"
"foo".include?("a") # => false
"foo"["a"] # => nil
In Ruby, anything that is not nil or false is considered true, so, for boolean tests the above tests are equivalent if you get a value or true, or if you get false or nil.
If you absolutely must have a boolean result, use the !! ("not not") trick which nicely converts a "truthy" value to its boolean complement, then back to that value's boolean complement.
true # => true
false # => false
'a' # => "a"
nil # => nil
!true # => false
!false # => true
!'a' # => false
!nil # => true
!!true # => true
!!false # => false
!!'a' # => true
!!nil # => false
Which lets us do:
!!"foo"["o"] # => true
!!"foo"["a"] # => false
This results in more compact code, which might not be what your particular coding-style wants. It pushes the Ruby code toward Perl or C code so weigh the compactness with readability and pick which style you want.
See String#[] for more information.
I am writing a small ruby app using sinatra and have a text input for input that I then convert to a flat using the .to_f method. However if the input is empty the .to_f still converts the empty string to a 0 value.
I would like it to be checked so if the input is blank/empty it does not attempt to convert it to a number.
Below is the code I have so far, I have tried adding .empty? to the end but it throws a method error.
weight = Weight.create(
:amount => params[:amount].to_f,
:user_id => current_user.id,
:created_at => Time.now
)
You have two basic options. The first is to use the ternary operator, and give a default value when the string is empty. The basic template is:
(params[:amount].empty?) ? <EMPTY EXPRESSION> : <NOT EMPTY EXPRESSION>
For example, to return nil when params[:amount] is empty:
weight = Weight.create(
:amount => (params[:amount].empty?) ? nil : params[:amount].to_f,
:user_id => current_user.id,
:created_at => Time.now
)
The second is to use Ruby's logical operators. The basic template is:
params[:amount].empty? && <EMPTY EXPRESSION> || <NOT EMPTY EXPRESSION>
For example, to raise an exception when params[:amount] is empty:
weight = Weight.create(
:amount => params[:amount].empty? && \
(raise ArgumentError.new('Bad :amount')) || params[:amount].to_f
:user_id => current_user.id,
:created_at => Time.now
)
Both ways can return nil or raise the exception. The choice is largely stylistic.
This is a more Java/EE way of doing things than is stricly necessary, but I find that parameter validation is such a common thing that it helps to define the functionality in one place and then just reuse it.
class ParamsExtractor
def get_float_parameter(params,key)
params[key] && !(params[key].nil? || params[key].to_s.strip == '') ? params[key].to_f : 0.0
end
end
weight = Weight.create(
:amount => ParamsExtractor.get_float_parameter(params, :amount),
:user_id => current_user.id,
:created_at => Time.now
)
There are additional things you can do (modules etc) but this is clear and easilly testable via RSpec
x = '' => ""
x.to_f unless x.empty? => nil
x = '1' => "1"
x.to_f unless x.empty? => 1.0
I use in my model following regular expression for getting a number that must to have a length 8. I do it this way:
validates_uniqueness_of :my_number, :with => /^[0-9]{8}$/, :message => "error message"
But this doesn't works me, if I set into the input "hahaha", I will get the "error message", if I set there 123, so I will get a success output, but that's wrong... I try to get a regular expression that will accepted always exact 8 digits...
Probably:
validates_format_of :my_number, :with => /\A[0-9]{8}\Z/
validates_uniqueness_of :my_number
Update: As #tadman points out in the comment, in Rails 3 you can combine validators:
validates :my_number, :uniqueness => true, :format => { :with => /^[0-9]{8}$/ }
Using old-style validation:
validates_uniqueness_of does not accept a with option, just validates_format_of does. So you might try:
validates_format_of :my_number, :with => /^[0-9]{8}$/, \
:message => "8 digits, please."
To validate uniqueness you might want to add another constraint.
I used Sphinx plugin for searching and configure it
define_index do
indexes First_name, :sortable => true
set_property :min_prefix_len => 1
end
Here First_name is column name.
But I was getting error of "search daemon fails to run". And when I made the column name as symbol it runs perfectly.
define_index do
indexes :First_name, :sortable => true
set_property :min_prefix_len => 1
end
Please make it clear to me.
http://www.robertsosinski.com/2009/01/11/the-difference-between-ruby-symbols-and-strings/
I think your example don't work because in first variant First_name is not a string. It's variable
"First_name" - will be a string
BTW , the difference between string and a symbol is that multiple symbols representing a single value are unique whereas this is not true with strings. For example:
irb(term)> :symbol.object_id
=> 746921
irb(term)> :symbol.object_id
=> 746921
irb(term)> "string".object_id
=> 298788231
irb(main):011:0> "string".object_id
=> 297533890
Also, symbol equality comparison is faster then String equality comparison since they are the same object whereas in a strings the values need to be compared instead the object id.
indexes First_name, :sortable => true
here rails treat First_name as a constant variable not the column.
so you can use
indexes :First_name, :sortable => true
or
indexes "First_name", :sortable => true
or
change the column First_name to first_name and then you can do this
indexes first_name, :sortable => true