Skip to content

Commit

Permalink
Fixes for user segment types. Added specs for most basic parts of user
Browse files Browse the repository at this point in the history
segments.
  • Loading branch information
Doug Youch committed May 20, 2010
1 parent 7952a25 commit 185ce24
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 20 deletions.
20 changes: 19 additions & 1 deletion app/models/user_segment/core_type.rb
@@ -1,7 +1,7 @@

class UserSegment::CoreType

@@datetime_format_options = ['day', 'days', 'week', 'weeks', 'month', 'months', 'year', 'years']
@@datetime_format_options = ['second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'year', 'years']
def self.datetime_format_options
@@datetime_format_options
end
Expand Down Expand Up @@ -37,17 +37,35 @@ def self.greater_than(cls, field, value)
cls.scoped(:conditions => ["#{field} > ?", value])
end

register_operation :greater_than_or_equal_to, [['Value', :integer]]

def self.greater_than_or_equal_to(cls, field, value)
cls.scoped(:conditions => ["#{field} >= ?", value])
end

register_operation :less_than, [['Value', :integer]]

def self.less_than(cls, field, value)
cls.scoped(:conditions => ["#{field} < ?", value])
end

register_operation :less_than_or_equal_to, [['Value', :integer]]

def self.less_than_or_equal_to(cls, field, value)
cls.scoped(:conditions => ["#{field} <= ?", value])
end

register_operation :equals, [['Value', :integer]]

def self.equals(cls, field, value)
cls.scoped(:conditions => ["#{field} = ?", value])
end

register_operation :is, [['Value', :integer]]

def self.is(cls, field, value)
self.equals(cls, field, value)
end
end

class StringType < UserSegment::FieldType
Expand Down
17 changes: 11 additions & 6 deletions app/models/user_segment/field_handler.rb
@@ -1,17 +1,22 @@

class UserSegment::FieldHandler

def self.user_segment_fields
@user_segment_fields ||= {}
end
def self.user_segment_fields; {}; end

def self.has_field?(field)
self.user_segment_fields[field.to_sym] ? true : false
end

def self.register_field(field, type, options={})
self.user_segment_fields[field.to_sym] = options.merge(:type => type)
self.user_segment_fields[field.to_sym][:name] ||= field.to_s.humanize
self.user_segment_fields[field.to_sym][:field] ||= field.to_sym
fields = self.user_segment_fields

fields[field.to_sym] = options.merge(:type => type)
fields[field.to_sym][:name] ||= field.to_s.humanize
fields[field.to_sym][:field] ||= field.to_sym

sing = class << self; self; end
sing.send :define_method, :user_segment_fields do
fields
end
end
end
24 changes: 15 additions & 9 deletions app/models/user_segment/field_type.rb
@@ -1,15 +1,15 @@

class UserSegment::FieldType

def self.user_segment_field_type_operations
@user_segment_field_type_operations ||= {}
end
def self.user_segment_field_type_operations; {}; end

def self.has_operation?(operation)
self.user_segment_field_type_operations[operation.to_sym] ? true : false
end

def self.register_operation(operation, args=[], options={})
operations = self.user_segment_field_type_operations

arguments = []
argument_names = []
argument_options = []
Expand All @@ -29,9 +29,14 @@ def self.register_operation(operation, args=[], options={})
argument_options << opts
end

name = options[:name] || operation.to_s.humanize

operations[operation.to_sym] = options.merge(:arguments => arguments, :argument_names => argument_names, :argument_options => argument_options)
operations[operation.to_sym][:name] ||= operation.to_s.humanize

self.user_segment_field_type_operations[operation.to_sym] = options.merge(:name => name, :arguments => arguments, :argument_names => argument_names, :argument_options => argument_options)
sing = class << self; self; end
sing.send :define_method, :user_segment_field_type_operations do
operations
end
end

# converts a string to the correct type
Expand All @@ -43,10 +48,10 @@ def self.convert_to(value, type, opts={})
when :float, :double
return value.to_f if value.is_a?(Numeric) || value =~ /^(\d+|\.\d+|\d+\.\d+)$/
when :string
return value
return value if value.is_a?(String)
when :date, :datetime
begin
return value if value.is_a?(::Time)
return value if value.is_a?(Time)
return Time.parse(value)
rescue
end
Expand All @@ -55,8 +60,9 @@ def self.convert_to(value, type, opts={})
return value if value
when :boolean
return value if value.is_a?(TrueClass) || value.is_a?(FalseClass)
return true if value == '1' || value.downcase == 'true'
return false if value == '0' || value.downcase == 'false'
value = value.downcase if value.is_a?(String)
return true if value == 1 || value == '1' || value == 'true'
return false if value == 0 || value == '0' || value == 'false'
end

nil
Expand Down
4 changes: 0 additions & 4 deletions app/models/user_segment/parser.rb

This file was deleted.

111 changes: 111 additions & 0 deletions spec/models/user_segment/core_type_spec.rb
@@ -0,0 +1,111 @@
require File.dirname(__FILE__) + "/../../spec_helper"

describe UserSegment::CoreType do

reset_domain_tables :end_users

describe "DateTimeType" do
before(:each) do
EndUser.push_target('test1@test.dev', :created_at => 2.days.ago)
EndUser.push_target('test2@test.dev', :created_at => 5.days.ago)
EndUser.push_target('test3@test.dev')

@type = UserSegment::CoreType::DateTimeType
end

it "should return users using before" do
@type.before(EndUser, :created_at, 1, 'day').count.should == 2
@type.before(EndUser, :created_at, 3, 'days').count.should == 1
@type.before(EndUser, :created_at, 6, 'days').count.should == 0
end

it "should return users using since" do
@type.since(EndUser, :created_at, 1, 'day').count.should == 1
@type.since(EndUser, :created_at, 3, 'days').count.should == 2
@type.since(EndUser, :created_at, 6, 'days').count.should == 3
end

it "should return users using between" do
@type.between(EndUser, :created_at, 1.day.ago, Time.now).count.should == 1
@type.between(EndUser, :created_at, 3.day.ago, Time.now).count.should == 2
@type.between(EndUser, :created_at, 6.day.ago, Time.now).count.should == 3
end
end

describe "NumberType" do
before(:each) do
EndUser.push_target('test1@test.dev', :user_level => 1)
EndUser.push_target('test2@test.dev', :user_level => 2)
EndUser.push_target('test3@test.dev', :user_level => 3)
EndUser.push_target('test4@test.dev', :user_level => 3)

@type = UserSegment::CoreType::NumberType
end

it "should return users using greater_than" do
@type.greater_than(EndUser, :user_level, 2).count.should == 2
@type.greater_than(EndUser, :user_level, 3).count.should == 0
end

it "should return users using greater_than_or_equal_to" do
@type.greater_than_or_equal_to(EndUser, :user_level, 1).count.should == 4
@type.greater_than_or_equal_to(EndUser, :user_level, 2).count.should == 3
@type.greater_than_or_equal_to(EndUser, :user_level, 4).count.should == 0
end

it "should return users using less_than" do
@type.less_than(EndUser, :user_level, 1).count.should == 0
@type.less_than(EndUser, :user_level, 2).count.should == 1
@type.less_than(EndUser, :user_level, 4).count.should == 4
end

it "should return users using less_than_or_equal_to" do
@type.less_than_or_equal_to(EndUser, :user_level, 1).count.should == 1
@type.less_than_or_equal_to(EndUser, :user_level, 2).count.should == 2
@type.less_than_or_equal_to(EndUser, :user_level, 3).count.should == 4
@type.less_than_or_equal_to(EndUser, :user_level, 4).count.should == 4
end

it "should return users using equals" do
@type.equals(EndUser, :user_level, 1).count.should == 1
@type.equals(EndUser, :user_level, 2).count.should == 1
@type.equals(EndUser, :user_level, 3).count.should == 2
@type.is(EndUser, :user_level, 3).count.should == 2
end
end

describe "StringType" do
before(:each) do
EndUser.push_target('test1@test.dev')
EndUser.push_target('test2@test.dev')
EndUser.push_target('test3@test.dev')
EndUser.push_target('test4@test.dev')

@type = UserSegment::CoreType::StringType
end

it "should return users using like" do
@type.like(EndUser, :email, 'test%@test.dev').count.should == 4
end

it "should return users using is" do
@type.is(EndUser, :email, 'test1@test.dev').count.should == 1
end
end

describe "BooleanType" do
before(:each) do
EndUser.push_target('test1@test.dev', :activated => true)
EndUser.push_target('test2@test.dev', :activated => true)
EndUser.push_target('test3@test.dev', :activated => true)
EndUser.push_target('test4@test.dev', :activated => false)

@type = UserSegment::CoreType::BooleanType
end

it "should return users using is" do
@type.is(EndUser, :activated, true).count.should == 3
@type.is(EndUser, :activated, false).count.should == 1
end
end
end
18 changes: 18 additions & 0 deletions spec/models/user_segment/field_handler_spec.rb
@@ -0,0 +1,18 @@
require File.dirname(__FILE__) + "/../../spec_helper"

describe UserSegment::FieldHandler do

it "should be able to register a field" do
UserSegment::FieldHandler.register_field(:created, UserSegment::CoreType::DateTimeType, :field => :created_at)
UserSegment::FieldHandler.has_field?(:created).should be_true
UserSegment::FieldHandler.user_segment_fields[:created][:field].should == :created_at
UserSegment::FieldHandler.user_segment_fields[:created][:type].should == UserSegment::CoreType::DateTimeType
UserSegment::FieldHandler.user_segment_fields[:created][:name].should == 'Created'

UserSegment::FieldHandler.register_field(:created, UserSegment::CoreType::DateTimeType, :field => :created_at, :name => 'EndUser.created')
UserSegment::FieldHandler.has_field?(:created).should be_true
UserSegment::FieldHandler.user_segment_fields[:created][:field].should == :created_at
UserSegment::FieldHandler.user_segment_fields[:created][:type].should == UserSegment::CoreType::DateTimeType
UserSegment::FieldHandler.user_segment_fields[:created][:name].should == 'EndUser.created'
end
end
62 changes: 62 additions & 0 deletions spec/models/user_segment/field_spec.rb
@@ -0,0 +1,62 @@
require File.dirname(__FILE__) + "/../../spec_helper"

describe UserSegment::Field do

reset_domain_tables :end_users

@handler = EndUserSegmentField.user_segment_fields_handler_info

before(:each) do
EndUser.push_target('test1@test.dev', :created_at => 2.days.ago, :activated => true)
EndUser.push_target('test2@test.dev', :created_at => 5.days.ago, :activated => false)
EndUser.push_target('test3@test.dev', :activated => false)
end

it "should be able to use handler" do
@field = UserSegment::Field.new :field => 'created', :operation => 'before', :arguments => [1, 'days']
@field.handler = @handler

@field.handler_class.should == EndUserSegmentField
@field.domain_model_class.should == EndUser
@field.end_user_field.should == :id
@field.model_field.should == :created_at
@field.type_class.should == UserSegment::CoreType::DateTimeType
@field.operation_arguments.should == [:integer, :option]
@field.valid_arguments?.should == true
@field.valid?.should == true
end

it "should return the count" do
@field = UserSegment::Field.new :field => 'created', :operation => 'before', :arguments => [1, 'days']
@field.handler = @handler
@field.valid?.should == true
@field.count.should == 2
@field.end_user_ids.length.should == 2

@field = UserSegment::Field.new :field => 'created', :operation => 'since', :arguments => [1, 'days']
@field.handler = @handler
@field.valid?.should == true
@field.count.should == 1
@field.end_user_ids.length.should == 1
end

it "should work with children" do
@field = UserSegment::Field.new :field => 'created', :operation => 'before', :arguments => [1, 'days'], :child => {:field => 'activated', :operation => 'is', :arguments => [true]}
@field.handler = @handler
@field.valid?.should == true
@field.count.should == 1
@field.end_user_ids.length.should == 1

@field = UserSegment::Field.new :field => 'created', :operation => 'before', :arguments => [1, 'days'], :child => {:field => 'activated', :operation => 'is', :arguments => [true], :child => {:field => 'email', :operation => 'like', :arguments => ['test%@test.dev']}}
@field.handler = @handler
@field.valid?.should == true
@field.count.should == 1
@field.end_user_ids.length.should == 1

@field = UserSegment::Field.new :field => 'created', :operation => 'before', :arguments => [1, 'days'], :child => {:field => 'activated', :operation => 'is', :arguments => [false], :child => {:field => 'email', :operation => 'like', :arguments => ['test%@test.dev']}}
@field.handler = @handler
@field.valid?.should == true
@field.count.should == 1
@field.end_user_ids.length.should == 1
end
end

0 comments on commit 185ce24

Please sign in to comment.