offroad 0.0.1 → 0.0.2
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/Rakefile +1 -1
- data/lib/app/models/offroad/received_record_state.rb +13 -7
- data/lib/mirror_data.rb +28 -6
- data/lib/model_extensions.rb +5 -5
- data/lib/offroad.rb +11 -0
- data/lib/version.rb +1 -1
- data/test/app_root/config/database-pg.yml +8 -0
- data/test/app_root/config/environment.rb +9 -0
- data/test/test_helper.rb +55 -7
- data/test/unit/mirror_data_test.rb +13 -1
- metadata +10 -7
    
        data/Rakefile
    CHANGED
    
    
| @@ -81,12 +81,18 @@ module Offroad | |
| 81 81 |  | 
| 82 82 | 
             
                  return unless remaining.size > 0
         | 
| 83 83 |  | 
| 84 | 
            -
                  # Reserve access to a block of local ids | 
| 85 | 
            -
                   | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
                   | 
| 89 | 
            -
             | 
| 84 | 
            +
                  # Reserve access to a block of local ids
         | 
| 85 | 
            +
                  if model.connection.adapter_name.downcase.include?("postgres")
         | 
| 86 | 
            +
                    nextval_cmd = model.connection.select_value("SELECT column_default FROM information_schema.columns WHERE table_name = '#{model.table_name}' AND column_name = '#{model.primary_key}'")
         | 
| 87 | 
            +
                    local_ids = model.connection.select_values("SELECT #{nextval_cmd} FROM generate_series(1,#{remaining.size})").map(&:to_i)
         | 
| 88 | 
            +
                  else
         | 
| 89 | 
            +
                    # Reserve access to a block of local ids by creating temporary records to advance the autoincrement counter
         | 
| 90 | 
            +
                    # TODO I'm pretty sure this is safe because it'll always be used in a transaction, but I should check
         | 
| 91 | 
            +
                    model.import([model.primary_key.to_sym], [[nil]]*remaining.size, :validate => false, :timestamps => false)
         | 
| 92 | 
            +
                    last_id = model.last(:select => model.primary_key, :order => model.primary_key).id
         | 
| 93 | 
            +
                    local_ids = ((last_id+1-remaining.size)..last_id).to_a
         | 
| 94 | 
            +
                    model.delete(local_ids)
         | 
| 95 | 
            +
                  end
         | 
| 90 96 |  | 
| 91 97 | 
             
                  # Create the corresponding RRSes
         | 
| 92 98 | 
             
                  model_state_id = model.offroad_model_state.id
         | 
| @@ -101,7 +107,7 @@ module Offroad | |
| 101 107 | 
             
                  # Finally do the redirection to the new ids
         | 
| 102 108 | 
             
                  remaining.each_key.each_with_index do |remote_id, i|
         | 
| 103 109 | 
             
                    remaining[remote_id].each do |r|
         | 
| 104 | 
            -
                      r[column] = local_ids | 
| 110 | 
            +
                      r[column] = local_ids[i]
         | 
| 105 111 | 
             
                    end
         | 
| 106 112 | 
             
                  end
         | 
| 107 113 | 
             
                end
         | 
    
        data/lib/mirror_data.rb
    CHANGED
    
    | @@ -89,17 +89,28 @@ module Offroad | |
| 89 89 | 
             
                end
         | 
| 90 90 |  | 
| 91 91 | 
             
                def delete_all_existing_database_records!
         | 
| 92 | 
            -
                   | 
| 93 | 
            -
                   | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 92 | 
            +
                  tables = ActiveRecord::Base.connection.tables
         | 
| 93 | 
            +
                  if ActiveRecord::Base.connection.adapter_name.downcase.include?("sqlite")
         | 
| 94 | 
            +
                    # Emptying sqlite_sequence resets SQLite's autoincrement counters.
         | 
| 95 | 
            +
                    # SQLite's autoincrement is nice in that it automatically picks largest ever id + 1.
         | 
| 96 | 
            +
                    # This means that after clearing sqlite_sequence and then populating database with manually-id'd rows,
         | 
| 97 | 
            +
                    # new records will be inserted with unique id's, no problem.
         | 
| 98 | 
            +
                    tables << "sqlite_sequence"
         | 
| 99 | 
            +
                  end
         | 
| 97 100 |  | 
| 98 101 | 
             
                  tables.each do |table|
         | 
| 99 | 
            -
                    next if table.start_with?(" | 
| 102 | 
            +
                    next if table.start_with?("virtual_") # Used in testing # FIXME Should pick something less likely to collide with app name
         | 
| 100 103 | 
             
                    next if table == "schema_migrations"
         | 
| 101 104 | 
             
                    ActiveRecord::Base.connection.execute "DELETE FROM #{table}"
         | 
| 102 105 | 
             
                  end
         | 
| 106 | 
            +
                    
         | 
| 107 | 
            +
                  if ActiveRecord::Base.connection.adapter_name.downcase.include?("postgres")
         | 
| 108 | 
            +
                    # Reset all sequences so that autoincremented ids start from 1 again
         | 
| 109 | 
            +
                    seqnames = ActiveRecord::Base.connection.select_values "SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'"
         | 
| 110 | 
            +
                    seqnames.each do |s|
         | 
| 111 | 
            +
                      ActiveRecord::Base.connection.execute "SELECT setval('#{s}', 1, false)"
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
                  end
         | 
| 103 114 | 
             
                end
         | 
| 104 115 |  | 
| 105 116 | 
             
                def write_data(tgt)
         | 
| @@ -292,6 +303,16 @@ module Offroad | |
| 292 303 | 
             
                      batch.each { |rec| rec.after_offroad_upload }
         | 
| 293 304 | 
             
                    end
         | 
| 294 305 | 
             
                  end
         | 
| 306 | 
            +
                  if ActiveRecord::Base.connection.adapter_name.downcase.include?("postgres")
         | 
| 307 | 
            +
                    # Need to adjust the sequences so that records inserted from this point on don't collide with existing ids
         | 
| 308 | 
            +
                    cols = ActiveRecord::Base.connection.select_rows "select table_name, column_name, column_default from information_schema.columns WHERE column_default like 'nextval%'"
         | 
| 309 | 
            +
                    cols.each do |table_name, column_name, column_default|
         | 
| 310 | 
            +
                      if column_default =~ /nextval\('(.+)'(?:::.+)?\)/
         | 
| 311 | 
            +
                        seqname = $1
         | 
| 312 | 
            +
                        ActiveRecord::Base.connection.execute "SELECT setval('#{seqname}', (SELECT MAX(\"#{column_name}\") FROM \"#{table_name}\"))"
         | 
| 313 | 
            +
                      end
         | 
| 314 | 
            +
                    end
         | 
| 315 | 
            +
                  end
         | 
| 295 316 | 
             
                end
         | 
| 296 317 |  | 
| 297 318 | 
             
                def import_non_initial_model_cargo(cs, model)
         | 
| @@ -335,6 +356,7 @@ module Offroad | |
| 335 356 | 
             
                end
         | 
| 336 357 |  | 
| 337 358 | 
             
                def validate_imported_models(cs)
         | 
| 359 | 
            +
                  Offroad::group_base_model.connection.clear_query_cache
         | 
| 338 360 | 
             
                  while @imported_models_to_validate.size > 0
         | 
| 339 361 | 
             
                    model = @imported_models_to_validate.pop
         | 
| 340 362 | 
             
                    rrs_source = Offroad::ReceivedRecordState.for_model_and_group_if_apropos(model, @group)
         | 
    
        data/lib/model_extensions.rb
    CHANGED
    
    | @@ -35,13 +35,13 @@ module Offroad | |
| 35 35 | 
             
                    named_scope :owned_by_offroad_group, lambda { |group| { :conditions => { :id => group.id } } }
         | 
| 36 36 | 
             
                    named_scope :offline_groups, {
         | 
| 37 37 | 
             
                      :joins =>
         | 
| 38 | 
            -
                      "INNER JOIN  | 
| 38 | 
            +
                      "INNER JOIN \"#{Offroad::GroupState.table_name}\" ON \"#{Offroad::GroupState.table_name}\".app_group_id = \"#{table_name}\".\"#{primary_key}\""
         | 
| 39 39 | 
             
                    }
         | 
| 40 40 | 
             
                    named_scope :online_groups, {
         | 
| 41 41 | 
             
                      :joins =>
         | 
| 42 | 
            -
                      "LEFT JOIN  | 
| 42 | 
            +
                      "LEFT JOIN \"#{Offroad::GroupState.table_name}\" ON \"#{Offroad::GroupState.table_name}\".app_group_id = \"#{table_name}\".\"#{primary_key}\"",
         | 
| 43 43 | 
             
                      :conditions =>
         | 
| 44 | 
            -
                      " | 
| 44 | 
            +
                      "\"#{Offroad::GroupState.table_name}\".app_group_id IS NULL"
         | 
| 45 45 | 
             
                    }
         | 
| 46 46 | 
             
                  when :group_owned then
         | 
| 47 47 | 
             
                    named_scope :owned_by_offroad_group, lambda { |group| args_for_ownership_scope(group) }
         | 
| @@ -117,10 +117,10 @@ module Offroad | |
| 117 117 | 
             
                  assoc = offroad_parent_assoc
         | 
| 118 118 | 
             
                  while true
         | 
| 119 119 | 
             
                    if assoc.klass.offroad_group_base?
         | 
| 120 | 
            -
                      conditions << " | 
| 120 | 
            +
                      conditions << "\"#{assoc_owner.table_name}\".\"#{assoc.primary_key_name}\" = #{group.id}"
         | 
| 121 121 | 
             
                      break
         | 
| 122 122 | 
             
                    else
         | 
| 123 | 
            -
                      conditions << " | 
| 123 | 
            +
                      conditions << "\"#{assoc_owner.table_name}\".\"#{assoc.primary_key_name}\" = \"#{assoc.klass.table_name}\".\"#{assoc.klass.primary_key}\""
         | 
| 124 124 | 
             
                      included_assocs << assoc
         | 
| 125 125 | 
             
                      assoc_owner = assoc.klass
         | 
| 126 126 | 
             
                      assoc = assoc.klass.offroad_parent_assoc
         | 
    
        data/lib/offroad.rb
    CHANGED
    
    | @@ -11,6 +11,17 @@ $LOAD_PATH << path | |
| 11 11 | 
             
            ActiveSupport::Dependencies.autoload_paths << path
         | 
| 12 12 |  | 
| 13 13 | 
             
            require 'ar-extensions' # External dependency
         | 
| 14 | 
            +
            # Monkey patch a bug in ar-extensions which breaks postgres compatibility
         | 
| 15 | 
            +
            module ActiveRecord # :nodoc:
         | 
| 16 | 
            +
              module ConnectionAdapters # :nodoc:
         | 
| 17 | 
            +
                class AbstractAdapter # :nodoc:
         | 
| 18 | 
            +
                  def next_value_for_sequence(sequence_name)
         | 
| 19 | 
            +
                    %{nextval('#{sequence_name}')}
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| 14 25 |  | 
| 15 26 | 
             
            require 'controller_extensions'
         | 
| 16 27 | 
             
            class ActionController::Base
         | 
    
        data/lib/version.rb
    CHANGED
    
    
| @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            require File.join(File.dirname(__FILE__), 'boot')
         | 
| 2 2 |  | 
| 3 | 
            +
            RAILS_GEM_VERSION = '2.3.11'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            Rails::Initializer.run do |config|
         | 
| 4 6 | 
             
              config.cache_classes = false
         | 
| 5 7 | 
             
              config.whiny_nils = true
         | 
| @@ -12,4 +14,11 @@ Rails::Initializer.run do |config| | |
| 12 14 | 
             
              else
         | 
| 13 15 | 
             
                HOBO_TEST_MODE = false
         | 
| 14 16 | 
             
              end
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
              if ENV['PSQL_TEST_MODE']
         | 
| 19 | 
            +
                puts "Using postgresql for a test database"
         | 
| 20 | 
            +
                config.database_configuration_file = "#{RAILS_ROOT}/config/database-pg.yml"
         | 
| 21 | 
            +
              else
         | 
| 22 | 
            +
                puts "Using sqlite for a test database"
         | 
| 23 | 
            +
              end
         | 
| 15 24 | 
             
            end
         | 
    
        data/test/test_helper.rb
    CHANGED
    
    | @@ -30,7 +30,11 @@ end | |
| 30 30 | 
             
            module Test::Unit::Util::BacktraceFilter
         | 
| 31 31 | 
             
              def filter_backtrace(backtrace, prefix = nil)
         | 
| 32 32 | 
             
                backtrace = backtrace.select do |e|
         | 
| 33 | 
            -
                   | 
| 33 | 
            +
                  if ENV['FULL_BACKTRACE']
         | 
| 34 | 
            +
                    true
         | 
| 35 | 
            +
                  else
         | 
| 36 | 
            +
                    e.include?("offroad") || !(e.include?("/ruby/") || e.include?("/gems/"))
         | 
| 37 | 
            +
                  end
         | 
| 34 38 | 
             
                end
         | 
| 35 39 |  | 
| 36 40 | 
             
                common_prefix = nil
         | 
| @@ -101,12 +105,24 @@ class VirtualTestDatabase | |
| 101 105 | 
             
              end
         | 
| 102 106 |  | 
| 103 107 | 
             
              def delete_all_rows
         | 
| 104 | 
            -
                tables =  | 
| 108 | 
            +
                tables = ActiveRecord::Base.connection.tables
         | 
| 109 | 
            +
                if ActiveRecord::Base.connection.adapter_name.downcase.include?("sqlite")
         | 
| 110 | 
            +
                  tables << "sqlite_sequence"
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 105 113 | 
             
                tables.each do |table|
         | 
| 106 | 
            -
                  next if table.start_with?(" | 
| 114 | 
            +
                  next if table.downcase.start_with?("virtual_")
         | 
| 107 115 | 
             
                  next if table == "schema_migrations"
         | 
| 108 116 | 
             
                  ActiveRecord::Base.connection.execute "DELETE FROM #{table}"
         | 
| 109 117 | 
             
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                if ActiveRecord::Base.connection.adapter_name.downcase.include?("postgres")
         | 
| 120 | 
            +
                  # Reset all sequences so that autoincremented ids start from 1 again
         | 
| 121 | 
            +
                  seqnames = ActiveRecord::Base.connection.select_values "SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'"
         | 
| 122 | 
            +
                  seqnames.each do |s|
         | 
| 123 | 
            +
                    ActiveRecord::Base.connection.execute "SELECT setval('#{s}', 1, false)"
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                end
         | 
| 110 126 | 
             
              end
         | 
| 111 127 |  | 
| 112 128 | 
             
              protected
         | 
| @@ -118,11 +134,11 @@ class VirtualTestDatabase | |
| 118 134 | 
             
              private
         | 
| 119 135 |  | 
| 120 136 | 
             
              def normal_prefix
         | 
| 121 | 
            -
                " | 
| 137 | 
            +
                "virtual_normal_#{@prefix}_"
         | 
| 122 138 | 
             
              end
         | 
| 123 139 |  | 
| 124 140 | 
             
              def fresh_prefix
         | 
| 125 | 
            -
                " | 
| 141 | 
            +
                "virtual_fresh_#{@prefix}_"
         | 
| 126 142 | 
             
              end
         | 
| 127 143 |  | 
| 128 144 | 
             
              def put_away
         | 
| @@ -147,13 +163,16 @@ class VirtualTestDatabase | |
| 147 163 | 
             
              end
         | 
| 148 164 |  | 
| 149 165 | 
             
              def copy_tables(src_prefix, dst_prefix)
         | 
| 150 | 
            -
                tables =  | 
| 166 | 
            +
                tables = ActiveRecord::Base.connection.tables
         | 
| 167 | 
            +
                if ActiveRecord::Base.connection.adapter_name.downcase.include?("sqlite")
         | 
| 168 | 
            +
                  tables << "sqlite_sequence"
         | 
| 169 | 
            +
                end
         | 
| 151 170 | 
             
                tables.each do |src_table|
         | 
| 152 171 | 
             
                  next if src_table.end_with?("schema_migrations")
         | 
| 153 172 | 
             
                  next unless src_table.start_with?(src_prefix)
         | 
| 154 173 | 
             
                  next if dst_prefix != "" && src_table.start_with?(dst_prefix)
         | 
| 155 174 | 
             
                  dst_table = dst_prefix + src_table[(src_prefix.size)..(src_table.size)]
         | 
| 156 | 
            -
                  next if src_table.start_with?(" | 
| 175 | 
            +
                  next if src_table.downcase.start_with?("virtual_") && dst_table.downcase.start_with?("virtual_")
         | 
| 157 176 | 
             
                  if tables.include?(dst_table)
         | 
| 158 177 | 
             
                    ActiveRecord::Base.connection.execute "DELETE FROM #{dst_table}"
         | 
| 159 178 | 
             
                    ActiveRecord::Base.connection.execute "INSERT INTO #{dst_table} SELECT * FROM #{src_table}"
         | 
| @@ -161,6 +180,24 @@ class VirtualTestDatabase | |
| 161 180 | 
             
                    ActiveRecord::Base.connection.execute "CREATE TABLE #{dst_table} AS SELECT * FROM #{src_table}"
         | 
| 162 181 | 
             
                  end
         | 
| 163 182 | 
             
                end
         | 
| 183 | 
            +
                    
         | 
| 184 | 
            +
                if ActiveRecord::Base.connection.adapter_name.downcase.include?("postgres")
         | 
| 185 | 
            +
                  # Manage postgresql sequences by keeping non-current sequence vals backed up in Ruby
         | 
| 186 | 
            +
                  @pg_seq_vals ||= {}
         | 
| 187 | 
            +
                  if src_prefix.blank?
         | 
| 188 | 
            +
                    # PG Sequences -> Ruby
         | 
| 189 | 
            +
                    @pg_seq_vals[dst_prefix] ||= {}
         | 
| 190 | 
            +
                    seqnames = ActiveRecord::Base.connection.select_values "SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'"
         | 
| 191 | 
            +
                    seqnames.each do |s|
         | 
| 192 | 
            +
                      @pg_seq_vals[dst_prefix][s] = ActiveRecord::Base.connection.select_value "SELECT last_value FROM \"#{s}\""
         | 
| 193 | 
            +
                    end
         | 
| 194 | 
            +
                  else
         | 
| 195 | 
            +
                    # Ruby -> PG Sequences
         | 
| 196 | 
            +
                    @pg_seq_vals[src_prefix].each do |s, v|
         | 
| 197 | 
            +
                      ActiveRecord::Base.connection.execute "SELECT setval('#{s}', #{v}, true)"
         | 
| 198 | 
            +
                    end
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
                end
         | 
| 164 201 | 
             
              end
         | 
| 165 202 |  | 
| 166 203 | 
             
              def backup_instance_vars(key)
         | 
| @@ -280,11 +317,22 @@ end | |
| 280 317 | 
             
            class Test::Unit::TestCase
         | 
| 281 318 | 
             
              @@online_database = nil
         | 
| 282 319 | 
             
              @@offline_database = nil
         | 
| 320 | 
            +
              @@initial_setup = false
         | 
| 283 321 |  | 
| 284 322 | 
             
              include Test::Unit::Util::BacktraceFilter
         | 
| 285 323 |  | 
| 286 324 | 
             
              def setup
         | 
| 287 325 | 
             
                begin
         | 
| 326 | 
            +
                  unless @@initial_setup
         | 
| 327 | 
            +
                    if ActiveRecord::Base.connection.adapter_name.downcase.include?("postgresql")
         | 
| 328 | 
            +
                      puts "Dropping all postgresql tables"
         | 
| 329 | 
            +
                      tables = ActiveRecord::Base.connection.tables.each do |table|
         | 
| 330 | 
            +
                        ActiveRecord::Base.connection.execute "DROP TABLE #{table}"
         | 
| 331 | 
            +
                      end
         | 
| 332 | 
            +
                    end
         | 
| 333 | 
            +
                    @@initial_setup = true
         | 
| 334 | 
            +
                  end
         | 
| 335 | 
            +
             | 
| 288 336 | 
             
                  unless ActiveRecord::Base.connection.table_exists?("schema_migrations")
         | 
| 289 337 | 
             
                    # FIXME : Figure out why ActionController::TestCase keeps on deleting all the tables before each method
         | 
| 290 338 |  | 
| @@ -49,11 +49,23 @@ class MirrorDataTest < Test::Unit::TestCase | |
| 49 49 | 
             
                assert_equal @offline_group.id, group_state.app_group_id
         | 
| 50 50 | 
             
              end
         | 
| 51 51 |  | 
| 52 | 
            +
              def strip_msecs_in_values(hash)
         | 
| 53 | 
            +
                new_hash = {}
         | 
| 54 | 
            +
                hash.each do |k,v|
         | 
| 55 | 
            +
                  if v.is_a?(DateTime) || v.is_a?(Time)
         | 
| 56 | 
            +
                    new_hash[k] = v.to_i
         | 
| 57 | 
            +
                  else
         | 
| 58 | 
            +
                    new_hash[k] = v
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                new_hash
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 52 64 | 
             
              def assert_single_model_cargo_entry_matches(cs, record)
         | 
| 53 65 | 
             
                record.reload
         | 
| 54 66 | 
             
                data_name = Offroad::MirrorData.send(:data_cargo_name_for_model, record.class)
         | 
| 55 67 | 
             
                assert_single_cargo_section_named cs, data_name
         | 
| 56 | 
            -
                assert_equal record.attributes, cs.first_cargo_element(data_name).attributes
         | 
| 68 | 
            +
                assert_equal strip_msecs_in_values(record.attributes), strip_msecs_in_values(cs.first_cargo_element(data_name).attributes)
         | 
| 57 69 | 
             
              end
         | 
| 58 70 |  | 
| 59 71 | 
             
              def assert_record_not_present(cs, record)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: offroad
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 27
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 8 | 
             
              - 0
         | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 0.0. | 
| 9 | 
            +
              - 2
         | 
| 10 | 
            +
              version: 0.0.2
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - David Mike Simon
         | 
| @@ -15,7 +15,7 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2011-04- | 
| 18 | 
            +
            date: 2011-04-15 00:00:00 -05:00
         | 
| 19 19 | 
             
            default_executable: 
         | 
| 20 20 | 
             
            dependencies: 
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -24,12 +24,14 @@ dependencies: | |
| 24 24 | 
             
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 25 25 | 
             
                none: false
         | 
| 26 26 | 
             
                requirements: 
         | 
| 27 | 
            -
                - - " | 
| 27 | 
            +
                - - "="
         | 
| 28 28 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 29 | 
            -
                    hash:  | 
| 29 | 
            +
                    hash: 51
         | 
| 30 30 | 
             
                    segments: 
         | 
| 31 31 | 
             
                    - 0
         | 
| 32 | 
            -
                     | 
| 32 | 
            +
                    - 9
         | 
| 33 | 
            +
                    - 4
         | 
| 34 | 
            +
                    version: 0.9.4
         | 
| 33 35 | 
             
              type: :runtime
         | 
| 34 36 | 
             
              version_requirements: *id001
         | 
| 35 37 | 
             
            description: Offroad manages offline instances of a Rails app on computers without Internet access. The online and offline instances can communicate via mirror files, transported by the user via thumbdrive, burned CD, etc.
         | 
| @@ -79,6 +81,7 @@ files: | |
| 79 81 | 
             
            - test/app_root/app/views/group/upload_up_mirror.html.erb
         | 
| 80 82 | 
             
            - test/app_root/app/views/layouts/mirror.html.erb
         | 
| 81 83 | 
             
            - test/app_root/config/boot.rb
         | 
| 84 | 
            +
            - test/app_root/config/database-pg.yml
         | 
| 82 85 | 
             
            - test/app_root/config/database.yml
         | 
| 83 86 | 
             
            - test/app_root/config/environment.rb
         | 
| 84 87 | 
             
            - test/app_root/config/environments/test.rb
         |