facemock 0.0.4 → 0.0.5
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.
- data/.coveralls.yml +1 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +6 -0
- data/db/.gitkeep +0 -0
- data/facemock.gemspec +31 -0
- data/lib/facemock/config.rb +88 -0
- data/lib/facemock/database/application.rb +20 -0
- data/lib/facemock/database/permission.rb +21 -0
- data/lib/facemock/database/table.rb +340 -0
- data/lib/facemock/database/user.rb +26 -0
- data/lib/facemock/database.rb +121 -0
- data/lib/facemock/errors.rb +7 -0
- data/lib/facemock/fb_graph/application/test_users.rb +36 -0
- data/lib/facemock/fb_graph/application/user/permission.rb +10 -0
- data/lib/facemock/fb_graph/application/user.rb +69 -0
- data/lib/facemock/fb_graph/application.rb +48 -0
- data/lib/facemock/fb_graph/user.rb +13 -0
- data/lib/facemock/fb_graph.rb +30 -0
- data/lib/facemock/version.rb +3 -0
- data/lib/facemock.rb +19 -0
- data/spec/facemock/config_spec.rb +185 -0
- data/spec/facemock/database/application_spec.rb +73 -0
- data/spec/facemock/database/permission_spec.rb +52 -0
- data/spec/facemock/database/tables_spec.rb +728 -0
- data/spec/facemock/database/user_spec.rb +169 -0
- data/spec/facemock/database_spec.rb +270 -0
- data/spec/facemock/errors_spec.rb +9 -0
- data/spec/facemock/fb_graph/application/test_users_spec.rb +155 -0
- data/spec/facemock/fb_graph/application/user_spec.rb +208 -0
- data/spec/facemock/fb_graph/application_spec.rb +132 -0
- data/spec/facemock/fb_graph/user_spec.rb +36 -0
- data/spec/facemock/fb_graph_spec.rb +47 -0
- data/spec/facemock_spec.rb +74 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/tables_helper.rb +46 -0
- metadata +64 -3
| @@ -0,0 +1,340 @@ | |
| 1 | 
            +
            require 'facemock/database'
         | 
| 2 | 
            +
            require 'sqlite3'
         | 
| 3 | 
            +
            require 'hashie'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Facemock
         | 
| 6 | 
            +
              class Database
         | 
| 7 | 
            +
                class Table
         | 
| 8 | 
            +
                  # 以下は継承先でオーバーライド必須
         | 
| 9 | 
            +
                  #  * TABLE_NAME, COLUMN_NAMES
         | 
| 10 | 
            +
                  #  * initialize()
         | 
| 11 | 
            +
                  TABLE_NAME = :tables
         | 
| 12 | 
            +
                  COLUMN_NAMES = [:id, :text, :active, :number, :created_at]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def initialize(options={})
         | 
| 15 | 
            +
                    opts = Hashie::Mash.new(options)
         | 
| 16 | 
            +
                    self.id = opts.id
         | 
| 17 | 
            +
                    self.text = opts.text
         | 
| 18 | 
            +
                    self.active = opts.active || false
         | 
| 19 | 
            +
                    self.number = opts.number
         | 
| 20 | 
            +
                    self.created_at = opts.created_at
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def save!(options={})
         | 
| 24 | 
            +
                    persisted? ? update!(options) : insert!(options)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def update_attributes!(options)
         | 
| 28 | 
            +
                    # カラムに含まれるかどうかの確認。なければNoMethodError
         | 
| 29 | 
            +
                    options.each_key {|key| self.send(key) }
         | 
| 30 | 
            +
                    if persisted?
         | 
| 31 | 
            +
                      update!(options)
         | 
| 32 | 
            +
                    else
         | 
| 33 | 
            +
                      insert!(options)
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def destroy
         | 
| 38 | 
            +
                    raise unless persisted?
         | 
| 39 | 
            +
                    execute "DELETE FROM #{table_name} WHERE ID = #{self.id};"
         | 
| 40 | 
            +
                    self
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def fetch
         | 
| 44 | 
            +
                    if persisted?
         | 
| 45 | 
            +
                      sql = "SELECT * FROM #{table_name} WHERE ID = #{self.id} LIMIT 1;"
         | 
| 46 | 
            +
                      records = execute sql
         | 
| 47 | 
            +
                      return nil unless record = records.first
         | 
| 48 | 
            +
                      set_attributes_from_record(record)
         | 
| 49 | 
            +
                      self
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  def method_missing(name, *args)
         | 
| 54 | 
            +
                    method_name = name.to_s.include?("=") ? name.to_s[0...-1].to_sym : name
         | 
| 55 | 
            +
                    case name
         | 
| 56 | 
            +
                    when :identifier  then return send(:id)
         | 
| 57 | 
            +
                    when :identifier= then return send(:id=, *args)
         | 
| 58 | 
            +
                    else
         | 
| 59 | 
            +
                      if column_names.include?(method_name) && args.size <= 1
         | 
| 60 | 
            +
                        if !name.to_s.include?("=") && args.empty?
         | 
| 61 | 
            +
                          define_column_getter(name)
         | 
| 62 | 
            +
                          return send(name)
         | 
| 63 | 
            +
                        else
         | 
| 64 | 
            +
                          define_column_setter(name)
         | 
| 65 | 
            +
                          return send(name, args.first)
         | 
| 66 | 
            +
                        end
         | 
| 67 | 
            +
                      else
         | 
| 68 | 
            +
                        super
         | 
| 69 | 
            +
                      end
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def self.all
         | 
| 74 | 
            +
                    records = execute "SELECT * FROM #{table_name};"
         | 
| 75 | 
            +
                    records_to_objects(records)
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def self.first
         | 
| 79 | 
            +
                    records = execute "SELECT * FROM #{table_name} LIMIT 1;"
         | 
| 80 | 
            +
                    record_to_object(records.first)
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  def self.last
         | 
| 84 | 
            +
                    records = execute "SELECT * FROM #{table_name} ORDER BY ID DESC LIMIT 1 ;"
         | 
| 85 | 
            +
                    record_to_object(records.first)
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  def self.where(column)
         | 
| 89 | 
            +
                    column_name = column.keys.first
         | 
| 90 | 
            +
                    value = column.values.first
         | 
| 91 | 
            +
                    column_value = (value.kind_of?(String)) ? "'" + value + "'" : value.to_s
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    records = execute "SELECT * FROM #{table_name} WHERE #{column_name} = #{column_value};"
         | 
| 94 | 
            +
                    records_to_objects(records)
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  def self.method_missing(name, *args)
         | 
| 98 | 
            +
                    if name =~ /^find_by_(.+)/ || name =~ /^find_all_by_(.+)/
         | 
| 99 | 
            +
                      column_name = $1
         | 
| 100 | 
            +
                    else
         | 
| 101 | 
            +
                      super
         | 
| 102 | 
            +
                    end
         | 
| 103 | 
            +
                    super unless column_names.include?(column_name.to_sym)
         | 
| 104 | 
            +
                    raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" unless args.size == 1
         | 
| 105 | 
            +
                    super unless define_find_method(name, column_name)
         | 
| 106 | 
            +
                    send(name, args.first)
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  def table_name
         | 
| 110 | 
            +
                    self.class.table_name
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  def column_names
         | 
| 114 | 
            +
                    self.class.column_names
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  def persisted?
         | 
| 118 | 
            +
                    !!(self.id && !(self.class.find_by_id(self.id).nil?))
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  def self.table_name
         | 
| 122 | 
            +
                    self::TABLE_NAME
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  def self.column_names
         | 
| 126 | 
            +
                    self::COLUMN_NAMES
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  def self.column_type(column_name)
         | 
| 130 | 
            +
                    return nil unless column_names.include?(column_name.to_s.to_sym)
         | 
| 131 | 
            +
                    table_info.send(column_name).type
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  def self.table_info
         | 
| 135 | 
            +
                    sql = "PRAGMA TABLE_INFO(#{table_name});"
         | 
| 136 | 
            +
                    records = execute sql
         | 
| 137 | 
            +
                    info = Hashie::Mash.new
         | 
| 138 | 
            +
                    records.each do |record|
         | 
| 139 | 
            +
                      column_info = Hashie::Mash.new(
         | 
| 140 | 
            +
                        { cid:         record[0],
         | 
| 141 | 
            +
                          name:        record[1].to_sym,
         | 
| 142 | 
            +
                          type:        record[2],
         | 
| 143 | 
            +
                          notnull:    (record[3] == 1),
         | 
| 144 | 
            +
                          dflt_value:  record[4],
         | 
| 145 | 
            +
                          pk:         (record[5] == 1) }
         | 
| 146 | 
            +
                      )
         | 
| 147 | 
            +
                      info.send(record[1] + "=", column_info)
         | 
| 148 | 
            +
                    end
         | 
| 149 | 
            +
                    info
         | 
| 150 | 
            +
                  end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                  private
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  def execute(sql)
         | 
| 155 | 
            +
                    self.class.execute(sql)
         | 
| 156 | 
            +
                  end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  def self.execute(sql)
         | 
| 159 | 
            +
                    database = Facemock::Database.new
         | 
| 160 | 
            +
                    records = database.connection.execute sql
         | 
| 161 | 
            +
                    if records.empty? && sql =~ /^INSERT /
         | 
| 162 | 
            +
                      records = database.connection.execute <<-SQL
         | 
| 163 | 
            +
                        SELECT * FROM #{table_name} WHERE ROWID = last_insert_rowid();
         | 
| 164 | 
            +
                      SQL
         | 
| 165 | 
            +
                    end
         | 
| 166 | 
            +
                    database.disconnect!
         | 
| 167 | 
            +
                    records
         | 
| 168 | 
            +
                  end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                  def self.record_to_object(record)
         | 
| 171 | 
            +
                    return nil unless record
         | 
| 172 | 
            +
                    self.new(record_to_hash(record))
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  def self.records_to_objects(records)
         | 
| 176 | 
            +
                    records.inject([]) do |objects, record|
         | 
| 177 | 
            +
                      objects << record_to_object(record)
         | 
| 178 | 
            +
                    end
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                  def record_to_hash(record)
         | 
| 182 | 
            +
                    self.class.record_to_hash(record)
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                  # 以下の形式のHashが返される
         | 
| 186 | 
            +
                  #   { id: x, ..., created_at: yyyy-mm-dd :hh:mm +xxxx }
         | 
| 187 | 
            +
                  def self.record_to_hash(record)
         | 
| 188 | 
            +
                    hash = Hashie::Mash.new
         | 
| 189 | 
            +
                    column_names.each_with_index do |column_name, index|
         | 
| 190 | 
            +
                      value = (record[index] == "") ? nil : record[index]
         | 
| 191 | 
            +
                      parsed_value = case column_type(column_name)
         | 
| 192 | 
            +
                      when "BOOLEAN"  then eval(value)
         | 
| 193 | 
            +
                      when "DATETIME" then Time.parse(value)
         | 
| 194 | 
            +
                      else  value
         | 
| 195 | 
            +
                      end
         | 
| 196 | 
            +
                      hash.send(column_name.to_s + "=", parsed_value)
         | 
| 197 | 
            +
                    end
         | 
| 198 | 
            +
                    hash
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                  def self.define_find_method(method_name, column_name)
         | 
| 202 | 
            +
                    case method_name
         | 
| 203 | 
            +
                    when /^find_by_(.+)/     then define_find_by_column(column_name)
         | 
| 204 | 
            +
                    when /^find_all_by_(.+)/ then define_find_all_by_column(column_name)
         | 
| 205 | 
            +
                    else false
         | 
| 206 | 
            +
                    end
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                  def self.define_find_by_column(column_name)
         | 
| 210 | 
            +
                    self.class_eval <<-EOF
         | 
| 211 | 
            +
                      def self.find_by_#{column_name}(value)
         | 
| 212 | 
            +
                        column_value = case value
         | 
| 213 | 
            +
                        when String then "'" + value + "'"
         | 
| 214 | 
            +
                        when Time   then "'" + value.to_s + "'"
         | 
| 215 | 
            +
                        else value.to_s
         | 
| 216 | 
            +
                        end
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                        sql  = "SELECT * FROM #{table_name} WHERE #{column_name} = "
         | 
| 219 | 
            +
                        sql += column_value + " LIMIT 1;"
         | 
| 220 | 
            +
                        records = execute sql
         | 
| 221 | 
            +
                        record_to_object(records.first)
         | 
| 222 | 
            +
                      end
         | 
| 223 | 
            +
                    EOF
         | 
| 224 | 
            +
                    true
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                  def self.define_find_all_by_column(column_name)
         | 
| 228 | 
            +
                    self.class_eval <<-EOF
         | 
| 229 | 
            +
                      def self.find_all_by_#{column_name}(value)
         | 
| 230 | 
            +
                        column_value = case value
         | 
| 231 | 
            +
                        when String then "'" + value + "'"
         | 
| 232 | 
            +
                        when Time   then "'" + value.to_s + "'"
         | 
| 233 | 
            +
                        else value.to_s
         | 
| 234 | 
            +
                        end
         | 
| 235 | 
            +
             | 
| 236 | 
            +
                        sql  = "SELECT * FROM #{table_name} WHERE #{column_name} = "
         | 
| 237 | 
            +
                        sql += column_value + ";"
         | 
| 238 | 
            +
                        records = execute sql
         | 
| 239 | 
            +
                        records_to_objects(records)
         | 
| 240 | 
            +
                      end
         | 
| 241 | 
            +
                    EOF
         | 
| 242 | 
            +
                    true
         | 
| 243 | 
            +
                  end
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                  def define_column_getter(name)
         | 
| 246 | 
            +
                    self.class.class_eval <<-EOF
         | 
| 247 | 
            +
                      def #{name}
         | 
| 248 | 
            +
                        self.instance_variable_get(:@#{name})
         | 
| 249 | 
            +
                      end
         | 
| 250 | 
            +
                    EOF
         | 
| 251 | 
            +
                  end
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                  def define_column_setter(name)
         | 
| 254 | 
            +
                    self.class.class_eval <<-EOF
         | 
| 255 | 
            +
                      def #{name}(value)
         | 
| 256 | 
            +
                        instance_variable_set(:@#{name.to_s.gsub("=", "")}, value)
         | 
| 257 | 
            +
                      end
         | 
| 258 | 
            +
                    EOF
         | 
| 259 | 
            +
                  end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                  # DatabaseへのINSERTが成功してからインスタンスのフィールド値を更新する
         | 
| 262 | 
            +
                  def insert!(options={})
         | 
| 263 | 
            +
                    opts = Hashie::Mash.new(options)
         | 
| 264 | 
            +
                    instance = self.class.new
         | 
| 265 | 
            +
                    column_names.each do |column_name|
         | 
| 266 | 
            +
                      if column_name != :created_at
         | 
| 267 | 
            +
                        if self.class.column_notnull(column_name) && column_is_empty?(column_name)
         | 
| 268 | 
            +
                          raise Facemock::Errors::ColumnTypeNotNull, "#{column_name} is null"
         | 
| 269 | 
            +
                        end
         | 
| 270 | 
            +
                        instance.send(column_name.to_s + "=", self.send(column_name))
         | 
| 271 | 
            +
                        if opts.send(column_name)
         | 
| 272 | 
            +
                          instance.send(column_name.to_s + "=", opts.send(column_name))
         | 
| 273 | 
            +
                        end
         | 
| 274 | 
            +
                      end
         | 
| 275 | 
            +
                    end
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                    target_column_names = if instance.id
         | 
| 278 | 
            +
                      column_names
         | 
| 279 | 
            +
                    else
         | 
| 280 | 
            +
                      column_names.select{|name| name != :id}
         | 
| 281 | 
            +
                    end
         | 
| 282 | 
            +
                    instance.created_at = Time.now
         | 
| 283 | 
            +
                    target_column_values = target_column_names.inject([]) do |ary, column_name|
         | 
| 284 | 
            +
                      ary << "'#{instance.send(column_name)}'"
         | 
| 285 | 
            +
                    end
         | 
| 286 | 
            +
                    values  = target_column_values.join(", ")
         | 
| 287 | 
            +
                    columns = target_column_names.join(', ')
         | 
| 288 | 
            +
             | 
| 289 | 
            +
                    sql = "INSERT INTO #{table_name}(#{columns}) VALUES ( #{values} );"
         | 
| 290 | 
            +
                    records = execute sql
         | 
| 291 | 
            +
                    set_attributes_from_record(records.first)
         | 
| 292 | 
            +
                    true
         | 
| 293 | 
            +
                  end
         | 
| 294 | 
            +
             | 
| 295 | 
            +
                  def update!(options={})
         | 
| 296 | 
            +
                    if options.empty?
         | 
| 297 | 
            +
                      column_names.each do |column_name|
         | 
| 298 | 
            +
                        if (value = self.send(column_name)) && column_name != :id
         | 
| 299 | 
            +
                          options[column_name] = value unless options.nil?
         | 
| 300 | 
            +
                        end
         | 
| 301 | 
            +
                      end
         | 
| 302 | 
            +
                    end
         | 
| 303 | 
            +
             | 
| 304 | 
            +
                    unless options.empty?
         | 
| 305 | 
            +
                      target_key_values = options.inject([]) do |ary, (key, value)|
         | 
| 306 | 
            +
                        ary << (value.kind_of?(Integer) ? "#{key} = #{value}" : "#{key} = '#{value}'")
         | 
| 307 | 
            +
                      end
         | 
| 308 | 
            +
                      sql = "UPDATE #{table_name} SET #{target_key_values.join(', ')} WHERE ID = #{self.id};"
         | 
| 309 | 
            +
                      execute sql
         | 
| 310 | 
            +
                    end
         | 
| 311 | 
            +
                    fetch
         | 
| 312 | 
            +
                    true
         | 
| 313 | 
            +
                  end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                  def set_attributes_from_record(record)
         | 
| 316 | 
            +
                    hash = record_to_hash(record)
         | 
| 317 | 
            +
                    column_names.each do |column_name|
         | 
| 318 | 
            +
                      method_name = column_name.to_s + "="
         | 
| 319 | 
            +
                      self.send(method_name, hash.send(column_name))
         | 
| 320 | 
            +
                    end
         | 
| 321 | 
            +
                  end
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                  def column_is_empty?(column_name)
         | 
| 324 | 
            +
                    return true if self.send(column_name).nil?
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                    return case self.class.column_type(column_name)
         | 
| 327 | 
            +
                    when "TEXT", "DATETIME", "BOOLEAN"
         | 
| 328 | 
            +
                      true if self.send(column_name) == ""
         | 
| 329 | 
            +
                    else
         | 
| 330 | 
            +
                      false
         | 
| 331 | 
            +
                    end
         | 
| 332 | 
            +
                  end
         | 
| 333 | 
            +
             | 
| 334 | 
            +
                  def self.column_notnull(column_name)
         | 
| 335 | 
            +
                    return nil unless column_names.include?(column_name.to_s.to_sym)
         | 
| 336 | 
            +
                    table_info.send(column_name).notnull
         | 
| 337 | 
            +
                  end
         | 
| 338 | 
            +
                end
         | 
| 339 | 
            +
              end
         | 
| 340 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'facemock/database'
         | 
| 2 | 
            +
            require 'facemock/database/table'
         | 
| 3 | 
            +
            require 'sqlite3'
         | 
| 4 | 
            +
            require 'hashie'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Facemock
         | 
| 7 | 
            +
              class Database
         | 
| 8 | 
            +
                class User < Table
         | 
| 9 | 
            +
                  TABLE_NAME = :users
         | 
| 10 | 
            +
                  COLUMN_NAMES = [:id, :name, :email, :password, :installed, :access_token, :application_id, :created_at]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def initialize(options={})
         | 
| 13 | 
            +
                    opts = Hashie::Mash.new(options)
         | 
| 14 | 
            +
                    @id             = (opts.id.to_i > 0) ? opts.id.to_i : ("10000" + (0..9).to_a.shuffle[0..10].join).to_i
         | 
| 15 | 
            +
                    @name           = opts.name         || rand(36**10).to_s(36)
         | 
| 16 | 
            +
                    @email          = opts.email        || name.gsub(" ", "_") + "@example.com"
         | 
| 17 | 
            +
                    @password       = opts.password     || rand(36**10).to_s(36)
         | 
| 18 | 
            +
                    @installed      = opts.installed    || false
         | 
| 19 | 
            +
                    @access_token   = opts.access_token || Digest::SHA512.hexdigest(identifier.to_s)
         | 
| 20 | 
            +
                    app_id = opts.application_id.to_i
         | 
| 21 | 
            +
                    @application_id = (app_id > 0) ? app_id : nil
         | 
| 22 | 
            +
                    @created_at     = opts.created_at
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,121 @@ | |
| 1 | 
            +
            require 'sqlite3'
         | 
| 2 | 
            +
            require 'facemock/database/table'
         | 
| 3 | 
            +
            require 'facemock/database/application'
         | 
| 4 | 
            +
            require 'facemock/database/user'
         | 
| 5 | 
            +
            require 'facemock/database/permission'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Facemock
         | 
| 8 | 
            +
              class Database
         | 
| 9 | 
            +
                ADAPTER = "sqlite3"
         | 
| 10 | 
            +
                DB_DIRECTORY = File.expand_path("../../../db", __FILE__)
         | 
| 11 | 
            +
                DEFAULT_DB_NAME = "facemock"
         | 
| 12 | 
            +
                TABLE_NAMES = [:applications, :users, :permissions]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                attr_reader :name
         | 
| 15 | 
            +
                attr_reader :connection
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize(name=nil)
         | 
| 18 | 
            +
                  @name = DEFAULT_DB_NAME
         | 
| 19 | 
            +
                  connect
         | 
| 20 | 
            +
                  create_tables
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def connect
         | 
| 24 | 
            +
                  @connection = SQLite3::Database.new filepath
         | 
| 25 | 
            +
                  @state = :connected
         | 
| 26 | 
            +
                  @connection
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def disconnect!
         | 
| 30 | 
            +
                  @connection.close
         | 
| 31 | 
            +
                  @state = :disconnected
         | 
| 32 | 
            +
                  nil
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
                  
         | 
| 35 | 
            +
                def connected?
         | 
| 36 | 
            +
                  @state == :connected
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def drop
         | 
| 40 | 
            +
                  disconnect!
         | 
| 41 | 
            +
                  File.delete(filepath) if File.exist?(filepath)
         | 
| 42 | 
            +
                  nil
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def clear
         | 
| 46 | 
            +
                  drop_tables
         | 
| 47 | 
            +
                  create_tables
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def create_tables
         | 
| 51 | 
            +
                  TABLE_NAMES.each do |table_name|
         | 
| 52 | 
            +
                    self.send "create_#{table_name}_table" unless table_exists?(table_name)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                  true
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def drop_table(table_name)
         | 
| 58 | 
            +
                  return false unless File.exist?(filepath) && table_exists?(table_name)
         | 
| 59 | 
            +
                  @connection.execute "drop table #{table_name};"
         | 
| 60 | 
            +
                  true
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def drop_tables
         | 
| 64 | 
            +
                  return false unless File.exist?(filepath)
         | 
| 65 | 
            +
                  TABLE_NAMES.each{|table_name| drop_table(table_name) }
         | 
| 66 | 
            +
                  true
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def filepath
         | 
| 70 | 
            +
                  name ||= @name
         | 
| 71 | 
            +
                  File.join(DB_DIRECTORY, "#{@name}.#{ADAPTER}")
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def table_exists?(table_name)
         | 
| 75 | 
            +
                  tables = @connection.execute "select * from sqlite_master"
         | 
| 76 | 
            +
                  tables.each do |table|
         | 
| 77 | 
            +
                    return true if table[1].to_s == table_name.to_s
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                  false
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                private
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def create_applications_table
         | 
| 85 | 
            +
                  @connection.execute <<-SQL
         | 
| 86 | 
            +
                    CREATE TABLE applications (
         | 
| 87 | 
            +
                      id          INTEGER   PRIMARY KEY AUTOINCREMENT,
         | 
| 88 | 
            +
                      secret      TEXT      NOT NULL,
         | 
| 89 | 
            +
                      created_at  DATETIME  NOT NULL,
         | 
| 90 | 
            +
                      UNIQUE(secret)
         | 
| 91 | 
            +
                    );
         | 
| 92 | 
            +
                  SQL
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def create_users_table
         | 
| 96 | 
            +
                  @connection.execute <<-SQL
         | 
| 97 | 
            +
                    CREATE TABLE users (
         | 
| 98 | 
            +
                      id              INTEGER  PRIMARY KEY AUTOINCREMENT,
         | 
| 99 | 
            +
                      name            TEXT      NOT NULL,
         | 
| 100 | 
            +
                      email           TEXT      NOT NULL,
         | 
| 101 | 
            +
                      password        TEXT      NOT NULL,
         | 
| 102 | 
            +
                      installed       BOOLEAN   NOT NULL,
         | 
| 103 | 
            +
                      access_token    TEXT      NOT NULL,
         | 
| 104 | 
            +
                      application_id  INTEGER   NOT NULL,
         | 
| 105 | 
            +
                      created_at      DATETIME  NOT NULL,
         | 
| 106 | 
            +
                      UNIQUE(access_token));
         | 
| 107 | 
            +
                  SQL
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def create_permissions_table
         | 
| 111 | 
            +
                  @connection.execute <<-SQL
         | 
| 112 | 
            +
                    CREATE TABLE permissions (
         | 
| 113 | 
            +
                      id          INTEGER   PRIMARY KEY AUTOINCREMENT,
         | 
| 114 | 
            +
                      name        TEXT      NOT NULL,
         | 
| 115 | 
            +
                      user_id     INTEGER   NOT NULL,
         | 
| 116 | 
            +
                      created_at  DATETIME  NOT NULL
         | 
| 117 | 
            +
                    );
         | 
| 118 | 
            +
                  SQL
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            require 'facemock/fb_graph/application/user'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Facemock
         | 
| 4 | 
            +
              module FbGraph
         | 
| 5 | 
            +
                class Application
         | 
| 6 | 
            +
                  class TestUsers < Array
         | 
| 7 | 
            +
                    DEFAULT_LIMIT = 50
         | 
| 8 | 
            +
                    DEFAULT_AFTER = 0
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    def initialize(application_id, options={})
         | 
| 11 | 
            +
                      @limit = limit = (options[:limit] && options[:limit] > 0) ? options[:limit] : DEFAULT_LIMIT
         | 
| 12 | 
            +
                      @after = after = (options[:after] && options[:after] > 0) ? options[:after] : DEFAULT_AFTER
         | 
| 13 | 
            +
                      @application_id = application_id
         | 
| 14 | 
            +
                      st = after
         | 
| 15 | 
            +
                      ed = after + limit - 1
         | 
| 16 | 
            +
                      users = User.find_all_by_application_id(application_id).sort_by{|u| u.created_at}
         | 
| 17 | 
            +
                      users = users.reverse[st..ed] || []
         | 
| 18 | 
            +
                      super(users)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    def collection
         | 
| 22 | 
            +
                      self
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                    
         | 
| 25 | 
            +
                    def next
         | 
| 26 | 
            +
                      options = { limit: @limit, after: @after + @limit }
         | 
| 27 | 
            +
                      TestUsers.new(@application_id, options)
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def select
         | 
| 31 | 
            +
                      { limit: DEFAULT_LIMIT, after: DEFAULT_AFTER }
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            require 'hashie'
         | 
| 2 | 
            +
            require 'facemock/fb_graph/application/user/permission'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Facemock
         | 
| 5 | 
            +
              module FbGraph
         | 
| 6 | 
            +
                class Application
         | 
| 7 | 
            +
                  class User < Facemock::Database::User
         | 
| 8 | 
            +
                    attr_reader :permission_objects
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    def initialize(options={})
         | 
| 11 | 
            +
                      opts = Hashie::Mash.new(options)
         | 
| 12 | 
            +
                      if opts.identifier
         | 
| 13 | 
            +
                        opts[:id] = opts.identifier
         | 
| 14 | 
            +
                        opts.delete(:identifier)
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                      super(opts)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      @permission_objects = User::Permission.find_all_by_user_id(self.id)
         | 
| 19 | 
            +
                      set_permissions(opts.permissions) if opts.permissions
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    def permissions
         | 
| 23 | 
            +
                      @permission_objects.inject([]) do |names, perm|
         | 
| 24 | 
            +
                        names << perm.name.to_sym
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def save!
         | 
| 29 | 
            +
                      super
         | 
| 30 | 
            +
                      @permission_objects.each do |permission|
         | 
| 31 | 
            +
                        permission.save!
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    def fetch
         | 
| 36 | 
            +
                      @permission_objects = User::Permission.find_all_by_user_id(self.id)
         | 
| 37 | 
            +
                      super
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def destroy
         | 
| 41 | 
            +
                      @permission_objects.each do |permission|
         | 
| 42 | 
            +
                        permission.destroy
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
                      super
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def revoke!
         | 
| 48 | 
            +
                      @permission_objects.each do |permission|
         | 
| 49 | 
            +
                        permission.destroy
         | 
| 50 | 
            +
                      end
         | 
| 51 | 
            +
                      @permission_objects = []
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    private
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def set_permissions(permissions_string)
         | 
| 57 | 
            +
                      permissions_string.gsub(/\s/, "").split(",").uniq.each do |permission_name|
         | 
| 58 | 
            +
                        unless @permission_objects.find{|perm| perm.name == permission_name}
         | 
| 59 | 
            +
                          @permission_objects << User::Permission.new(
         | 
| 60 | 
            +
                            name: permission_name,
         | 
| 61 | 
            +
                            user_id: self.id
         | 
| 62 | 
            +
                          )
         | 
| 63 | 
            +
                        end
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            require 'hashie'
         | 
| 2 | 
            +
            require 'facemock/config'
         | 
| 3 | 
            +
            require 'facemock/fb_graph/application/user'
         | 
| 4 | 
            +
            require 'facemock/fb_graph/application/test_users'
         | 
| 5 | 
            +
            require 'facemock/database/application'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Facemock
         | 
| 8 | 
            +
              module FbGraph
         | 
| 9 | 
            +
                class Application
         | 
| 10 | 
            +
                  attr_reader :identifier
         | 
| 11 | 
            +
                  attr_reader :secret
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(identifier, options={})
         | 
| 14 | 
            +
                    opts = Hashie::Mash.new(options)
         | 
| 15 | 
            +
                    if (identifier == :app && opts.access_token)
         | 
| 16 | 
            +
                      identifier = (0..9).to_a.shuffle[0..15].join
         | 
| 17 | 
            +
                      secret = opts.access_token
         | 
| 18 | 
            +
                    else
         | 
| 19 | 
            +
                      secret = opts.secret || rand(36**32).to_s(36)
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    @record = Facemock::Database::Application.new({id: identifier, secret: secret})
         | 
| 23 | 
            +
                    @record.save! unless Facemock::Database::Application.find_by_id(identifier)
         | 
| 24 | 
            +
                    @identifier = identifier.to_i
         | 
| 25 | 
            +
                    @secret     = secret
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def fetch
         | 
| 29 | 
            +
                    if @record = Facemock::Database::Application.find_by_id(@identifier)
         | 
| 30 | 
            +
                      @identifier = @record.id
         | 
| 31 | 
            +
                      @secret     = @record.secret
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                    self
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def test_user!(options={})
         | 
| 37 | 
            +
                    options.merge!({application_id: self.identifier})
         | 
| 38 | 
            +
                    user = User.new(options)
         | 
| 39 | 
            +
                    user.save!
         | 
| 40 | 
            +
                    user
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def test_users(options={})
         | 
| 44 | 
            +
                    TestUsers.new(self.identifier, options)
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require 'fb_graph'
         | 
| 2 | 
            +
            require 'facemock/config'
         | 
| 3 | 
            +
            require 'facemock/fb_graph/user'
         | 
| 4 | 
            +
            require 'facemock/fb_graph/application'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Facemock
         | 
| 7 | 
            +
              module FbGraph
         | 
| 8 | 
            +
                extend self
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def on(options={})
         | 
| 11 | 
            +
                  if ::FbGraph != Facemock::FbGraph
         | 
| 12 | 
            +
                    Object.const_set(:SourceFbGraph, ::FbGraph)
         | 
| 13 | 
            +
                    Object.send(:remove_const, :FbGraph) if Object.constants.include?(:FbGraph)
         | 
| 14 | 
            +
                    Object.const_set(:FbGraph, Facemock::FbGraph)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                  true
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def off
         | 
| 20 | 
            +
                  if ::FbGraph == Facemock::FbGraph
         | 
| 21 | 
            +
                    Object.send(:remove_const, :FbGraph) if Object.constants.include?(:FbGraph)
         | 
| 22 | 
            +
                    Object.const_set(:FbGraph, ::SourceFbGraph)
         | 
| 23 | 
            +
                    Object.send(:remove_const, :SourceFbGraph) if Object.constants.include?(:FbGraph)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  true
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                class InvalidToken < ::FbGraph::InvalidToken; end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         |