mongokit 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/mongokit.rb +39 -0
- data/lib/mongokit/address.rb +91 -0
- data/lib/mongokit/auto_increment.rb +66 -0
- data/lib/mongokit/auto_increment/counter.rb +35 -0
- data/lib/mongokit/auto_increment/formater.rb +72 -0
- data/lib/mongokit/csv_transformer.rb +97 -0
- data/lib/mongokit/csv_transformer/csv_io.rb +67 -0
- data/lib/mongokit/extensions/mongoid_document.rb +19 -0
- data/lib/mongokit/find_in_batch.rb +43 -0
- data/lib/mongokit/model_helpers.rb +75 -0
- data/lib/mongokit/models/auto_increment_counter.rb +40 -0
- data/lib/mongokit/secure_token.rb +65 -0
- data/lib/mongokit/utils/options.rb +62 -0
- data/lib/mongokit/version.rb +3 -0
- data/lib/mongokit/yaml_store.rb +48 -0
- data/mongokit.gemspec +27 -0
- metadata +127 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: b0207a9bfb1363e04a263ee0a60c68fecd226a25
         | 
| 4 | 
            +
              data.tar.gz: 382598e973bd393aeb8cf2d0224bd529e42d29d1
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: f6f794510f044bbadbb70d37634f56c4abe9afa6ffe6f28677bbc8b5d4374f2136ec52c2366b7bd94482879421667c38fe5001edc07675eac73602eb5bc0824a
         | 
| 7 | 
            +
              data.tar.gz: 93ae9fdc1f3851d39b8b40e9a2eba81bb048c9b547f176502b87f8afbac837d9d23dae861b823b281214fb7292edbd16a982071583104afb79da3eb099fe28ef
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/CODE_OF_CONDUCT.md
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            # Contributor Code of Conduct
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
         | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            The MIT License (MIT)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Copyright (c) 2015 Jiren[jirenpatel@gmail.com]
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 6 | 
            +
            of this software and associated documentation files (the "Software"), to deal
         | 
| 7 | 
            +
            in the Software without restriction, including without limitation the rights
         | 
| 8 | 
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         | 
| 9 | 
            +
            copies of the Software, and to permit persons to whom the Software is
         | 
| 10 | 
            +
            furnished to do so, subject to the following conditions:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            The above copyright notice and this permission notice shall be included in
         | 
| 13 | 
            +
            all copies or substantial portions of the Software.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 16 | 
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 17 | 
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 18 | 
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 19 | 
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 20 | 
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         | 
| 21 | 
            +
            THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            # Mongokit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/mongokit`. To experiment with that code, run `bin/console` for an interactive prompt.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            TODO: Delete this and the text above, and describe your gem
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## Installation
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Add this line to your application's Gemfile:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ```ruby
         | 
| 12 | 
            +
            gem 'mongokit', github: 'jiren/mongokit'
         | 
| 13 | 
            +
            ```
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            And then execute:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                $ bundle
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Or install it yourself as:
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                $ gem install mongokit # NOTE: It will not work because gem is not published
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ## Usage
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            TODO: Write usage instructions here
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ## Development
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ## Contributing
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            1. Fork it ( https://github.com/[my-github-username]/mongokit/fork )
         | 
| 36 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 37 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 38 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 39 | 
            +
            5. Create a new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            require "bundler/gem_tasks"
         | 
    
        data/bin/console
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "bundler/setup"
         | 
| 4 | 
            +
            require "mongokit"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # You can add fixtures and/or initialization code here to make experimenting
         | 
| 7 | 
            +
            # with your gem easier. You can also use a different console, if you like.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         | 
| 10 | 
            +
            # require "pry"
         | 
| 11 | 
            +
            # Pry.start
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "irb"
         | 
| 14 | 
            +
            IRB.start
         | 
    
        data/bin/setup
    ADDED
    
    
    
        data/lib/mongokit.rb
    ADDED
    
    | @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            require 'mongoid'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mongokit
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              MODULE_NAMES = %w(
         | 
| 6 | 
            +
                AutoIncrement
         | 
| 7 | 
            +
                SecureToken
         | 
| 8 | 
            +
                Address
         | 
| 9 | 
            +
                CsvTransformer
         | 
| 10 | 
            +
                ModelHelpers
         | 
| 11 | 
            +
              ).inject({}) do |result, module_name|
         | 
| 12 | 
            +
                result[module_name.underscore.to_sym] = module_name
         | 
| 13 | 
            +
                result
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              MODULE_NAMES.each do |module_name, const_name|
         | 
| 17 | 
            +
                autoload const_name, "mongokit/#{module_name}"
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              autoload :Options, 'mongokit/utils/options'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              MongokitError = Class.new(StandardError)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def self.modules
         | 
| 25 | 
            +
                MODULE_NAMES.values
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def self.config(options = {})
         | 
| 29 | 
            +
                options[:load] = Array(options[:load])
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                options[:load].each do |module_name|
         | 
| 32 | 
            +
                  require "mongokit/#{module_name}"
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            require 'mongokit/version'
         | 
| 38 | 
            +
            require 'mongokit/extensions/mongoid_document'
         | 
| 39 | 
            +
            require 'mongokit/find_in_batch'
         | 
| @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              module Address
         | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                # == Example
         | 
| 7 | 
            +
                #   class User
         | 
| 8 | 
            +
                #     include Mongoid::Document
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                #     mongokit :address
         | 
| 11 | 
            +
                #     has_address
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                #     # OR
         | 
| 14 | 
            +
                #     # has_address(except: [:latitude, :longitude])
         | 
| 15 | 
            +
                #     # has_address(replace: {address_1: :street_1, address_2: :street_2})
         | 
| 16 | 
            +
                #   end
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                #   user = User.create({
         | 
| 19 | 
            +
                #     address_1:   'Studio 103',
         | 
| 20 | 
            +
                #     address_2:   'The Business Centre',
         | 
| 21 | 
            +
                #     street:      '61 Wellfield Road',
         | 
| 22 | 
            +
                #     city:        'Roath',
         | 
| 23 | 
            +
                #     state:       'Cardiff',
         | 
| 24 | 
            +
                #     postal_code: 'CF24 3DG',
         | 
| 25 | 
            +
                #     country:     'England'
         | 
| 26 | 
            +
                #   })
         | 
| 27 | 
            +
                #
         | 
| 28 | 
            +
                #   user.full_address # Studio 103, The Business Centre, 61 Wellfield Road, Roath, Cardiff, CF24 3DG, England
         | 
| 29 | 
            +
                #
         | 
| 30 | 
            +
                module ClassMethods
         | 
| 31 | 
            +
                  include Options::Store
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  ADDRESS_FIELDS = {
         | 
| 34 | 
            +
                    address_1:   String,
         | 
| 35 | 
            +
                    address_2:   String,
         | 
| 36 | 
            +
                    street:      String,
         | 
| 37 | 
            +
                    city:        String,
         | 
| 38 | 
            +
                    state:       String,
         | 
| 39 | 
            +
                    postal_code: String,
         | 
| 40 | 
            +
                    country:     String,
         | 
| 41 | 
            +
                    latitude:    Float,
         | 
| 42 | 
            +
                    longitude:   Float
         | 
| 43 | 
            +
                  }.freeze
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def has_address(options = {})
         | 
| 46 | 
            +
                    fields = ADDRESS_FIELDS.dup
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    if options[:add]
         | 
| 49 | 
            +
                      if options[:add].is_a?(Array)
         | 
| 50 | 
            +
                        options[:add] = options[:add].inject({}){|r, f| r[f] = String; r}
         | 
| 51 | 
            +
                      else
         | 
| 52 | 
            +
                        fields.merge!(options[:add])
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    fields = Options.process(fields, options)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    fields.each do |name, type|
         | 
| 59 | 
            +
                      field name, type: type
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    mk_options.tap do |o|
         | 
| 63 | 
            +
                      o.put(:address_fields, fields.keys)
         | 
| 64 | 
            +
                      o.put(:full_address_fields, fields.reject{|f, _| f == :latitude || f == :longitude }.keys)
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def address_fields
         | 
| 69 | 
            +
                    mk_options.get(:address_fields)
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def full_address(obj, options = nil)
         | 
| 73 | 
            +
                    fields = mk_options.get(:full_address_fields)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    if options
         | 
| 76 | 
            +
                      if options[:only]
         | 
| 77 | 
            +
                        fields = options[:only]
         | 
| 78 | 
            +
                      elsif options[:except]
         | 
| 79 | 
            +
                        fields = fields - options[:except]
         | 
| 80 | 
            +
                      end
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    fields.map{|f| obj[f]}.compact.join(', ')
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                def full_address(options = nil)
         | 
| 88 | 
            +
                  self.class.full_address(self, options)
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            require 'mongokit/auto_increment/counter'
         | 
| 2 | 
            +
            require 'mongokit/auto_increment/formater'
         | 
| 3 | 
            +
            require 'mongokit/models/auto_increment_counter'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Mongokit
         | 
| 6 | 
            +
              module AutoIncrement
         | 
| 7 | 
            +
                extend ActiveSupport::Concern
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                included do
         | 
| 10 | 
            +
                  unless included_modules.include?(Mongoid::Timestamps)
         | 
| 11 | 
            +
                    include Mongoid::Timestamps
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                module ClassMethods
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  # == Example
         | 
| 18 | 
            +
                  #   class Order
         | 
| 19 | 
            +
                  #     include Mongoid::Document
         | 
| 20 | 
            +
                  #     mongokit :auto_increment
         | 
| 21 | 
            +
                  #
         | 
| 22 | 
            +
                  #     auto_increment :order_count,
         | 
| 23 | 
            +
                  #     auto_increment :order_no, pattern: "%Y%m#####"  # Default numner symbol is #
         | 
| 24 | 
            +
                  #   end
         | 
| 25 | 
            +
                  #
         | 
| 26 | 
            +
                  #   order = Order.create
         | 
| 27 | 
            +
                  #   order.order_count  # 1
         | 
| 28 | 
            +
                  #   order.order_no     # 20150500001
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  def auto_increment(attribute, _options = {})
         | 
| 31 | 
            +
                    options = {
         | 
| 32 | 
            +
                      number_symbol: '#',
         | 
| 33 | 
            +
                      start:  0,
         | 
| 34 | 
            +
                      step: 1
         | 
| 35 | 
            +
                    }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    options.merge!(_options)
         | 
| 38 | 
            +
                    options[:attribute] = attribute
         | 
| 39 | 
            +
                    options[:model] = self
         | 
| 40 | 
            +
                    options[:type] ||= Integer
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    if options[:pattern]
         | 
| 43 | 
            +
                      options[:time_format] = Mongokit::Counter.to_time_format(options[:pattern])
         | 
| 44 | 
            +
                      options[:type] = String
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    field(attribute, type: options[:type])
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    # create new record in counter collection
         | 
| 50 | 
            +
                    Models::AutoIncrementCounter.find_or_create_with_seed(options)
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    after_create do |doc|
         | 
| 53 | 
            +
                      doc.set(attribute => Mongokit::Counter.next(options))
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    define_method("reserve_#{attribute}!") do
         | 
| 57 | 
            +
                      set(attribute => Mongokit::Counter.next(options))
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    define_method("current_#{attribute}_counter") do
         | 
| 61 | 
            +
                      Models::AutoIncrementCounter.current_counter(options)
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              module Counter
         | 
| 3 | 
            +
                module_function
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def next(options)
         | 
| 6 | 
            +
                  record = Models::AutoIncrementCounter.where({
         | 
| 7 | 
            +
                    counter_model_name: options[:model].collection_name,
         | 
| 8 | 
            +
                    counter_field: options[:attribute]
         | 
| 9 | 
            +
                  }).find_and_modify({ '$inc' => { counter: options[:step] }}, new: true)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  return record.counter if options[:pattern].nil?
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  if outdated?(record, options[:time_format])
         | 
| 14 | 
            +
                    record.set(counter: options[:start] + options[:step])
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  Formater.new.format(record.counter, options)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def outdated?(record, time_format)
         | 
| 21 | 
            +
                  Time.now.strftime(time_format).to_i > record.updated_at.strftime(time_format).to_i
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def to_time_format(pattern)
         | 
| 25 | 
            +
                  event = String.new
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  event += '%Y' if pattern.include? '%y' or pattern.include? '%Y'
         | 
| 28 | 
            +
                  event += '%m' if pattern.include? '%m'
         | 
| 29 | 
            +
                  event += '%H' if pattern.include? '%H'
         | 
| 30 | 
            +
                  event += '%M' if pattern.include? '%M'
         | 
| 31 | 
            +
                  event += '%d' if pattern.include? '%d'
         | 
| 32 | 
            +
                  event
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,72 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              class Formater
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def format(number, options)
         | 
| 5 | 
            +
                  @options = options
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  build(number)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                private
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # gets the next number.
         | 
| 13 | 
            +
                # it prepends the prefix + counter + sufix
         | 
| 14 | 
            +
                # ex:
         | 
| 15 | 
            +
                #   "%Y####BANK"
         | 
| 16 | 
            +
                #   %Y => prefix (year)
         | 
| 17 | 
            +
                #   #### => counter (starts with 0001)
         | 
| 18 | 
            +
                #   BANK => sufix
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                # if we are in 2011, the first model to be saved will get "20110001BANK"
         | 
| 21 | 
            +
                # the next model to be saved will get "20110002BANK", "20110003BANK"...
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                #   number => is the counter
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                #   next_custom_number(1)
         | 
| 26 | 
            +
                #   => "20110001BANK"
         | 
| 27 | 
            +
                def build(number)
         | 
| 28 | 
            +
                  prefix(@options[:pattern]).to_s +
         | 
| 29 | 
            +
                  counter(@options[:pattern], number).to_s +
         | 
| 30 | 
            +
                  sufix(@options[:pattern]).to_s
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def prefix(pattern)
         | 
| 34 | 
            +
                  prefx = extract_prefix(pattern)
         | 
| 35 | 
            +
                  expand_times(prefx.to_s)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def counter(pattern, n)
         | 
| 39 | 
            +
                  format_counter(digits_size(pattern), n)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def sufix(pattern)
         | 
| 43 | 
            +
                  sufx = extract_sufix(pattern)
         | 
| 44 | 
            +
                  expand_times(sufx.to_s)
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def format_counter(zeros, value)
         | 
| 48 | 
            +
                  "%0#{zeros}d" % value
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def extract_prefix(pattern)
         | 
| 52 | 
            +
                  # Company#### => Company
         | 
| 53 | 
            +
                  symbol = @options[:number_symbol]
         | 
| 54 | 
            +
                  (pattern =~ /^(\s|\d)*[^#{symbol}]+/ and $&)
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def extract_sufix(pattern)
         | 
| 58 | 
            +
                  # ###Company => Company
         | 
| 59 | 
            +
                  symbol = @options[:number_symbol]
         | 
| 60 | 
            +
                  (pattern =~ /[^#{symbol}]+$/ and $&)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def expand_times(pattern)
         | 
| 64 | 
            +
                  Time.now.strftime(pattern)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def digits_size(pattern)
         | 
| 68 | 
            +
                  symbol = @options[:number_symbol]
         | 
| 69 | 
            +
                  (pattern =~ /[#{symbol}]+/ and $&).length
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
            end
         | 
| @@ -0,0 +1,97 @@ | |
| 1 | 
            +
            require 'mongokit/csv_transformer/csv_io'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mongokit
         | 
| 4 | 
            +
              module CsvTransformer
         | 
| 5 | 
            +
                extend ActiveSupport::Concern
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                #
         | 
| 8 | 
            +
                # == Example
         | 
| 9 | 
            +
                #   class Address
         | 
| 10 | 
            +
                #     include Mongoid::Document
         | 
| 11 | 
            +
                #
         | 
| 12 | 
            +
                #     mongokit :csv_transformer
         | 
| 13 | 
            +
                #
         | 
| 14 | 
            +
                #     field :name
         | 
| 15 | 
            +
                #     field :region
         | 
| 16 | 
            +
                #     field :district
         | 
| 17 | 
            +
                #     field :state
         | 
| 18 | 
            +
                #     field :zip_code, type: Integer
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                #     csv_import_mapping :address, [:name, :zip_code], headers: true do |row, attrs|
         | 
| 21 | 
            +
                #       attrs[:zip_code] = attrs[:zip_code].to_i
         | 
| 22 | 
            +
                #     end
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                #     csv_export_mapping :address, [:zip_code, :name, :region] do |row, record|
         | 
| 25 | 
            +
                #       row[:zip_code] = "IN-#{row[:zip_code]}"
         | 
| 26 | 
            +
                #     end
         | 
| 27 | 
            +
                #   end
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                #   Address.from_address_csv('address.csv') # Import
         | 
| 30 | 
            +
                #   Address.to_address_csv('address.csv')   # Export
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                module ClassMethods
         | 
| 33 | 
            +
                  CsvTransformerError = Class.new(StandardError)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def csv_import_mapping(name, fields, options = {},  &block)
         | 
| 36 | 
            +
                    if respond_to?("from_#{name}_csv")
         | 
| 37 | 
            +
                      raise CsvTransformerError, "#{name} import mapper is already defined."
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    self.class.instance_eval do
         | 
| 41 | 
            +
                      define_method "from_#{name}_csv" do |file|
         | 
| 42 | 
            +
                        options[:columns] = fields
         | 
| 43 | 
            +
                        csv_import(file, options, &block)
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def csv_export_mapping(name, fields, options = {},  &block)
         | 
| 49 | 
            +
                    if respond_to?("to_#{name}_csv")
         | 
| 50 | 
            +
                      raise CsvTransformerError, "#{name} export mapper is already defined."
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    self.class.instance_eval do
         | 
| 54 | 
            +
                      define_method "to_#{name}_csv" do |file, criteria = nil|
         | 
| 55 | 
            +
                        options[:columns] = fields
         | 
| 56 | 
            +
                        criteria = self.all if criteria.nil?
         | 
| 57 | 
            +
                        csv_export(file, criteria, options, &block)
         | 
| 58 | 
            +
                      end
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def _csv_columns_(options = nil)
         | 
| 63 | 
            +
                    columns = fields.collect do |f, o|
         | 
| 64 | 
            +
                      if o.class == Mongoid::Fields::Standard && o.type != BSON::ObjectId
         | 
| 65 | 
            +
                        o.name
         | 
| 66 | 
            +
                      end
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    columns.compact!
         | 
| 70 | 
            +
                    options ? Options.process(options[:columns] || columns, options) : columns
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def csv_export(file, criteria, options = {}, &block)
         | 
| 74 | 
            +
                    columns = _csv_columns_(options)
         | 
| 75 | 
            +
                    io = CsvIO.new(:write, file, columns, options)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    criteria.in_batches do |records|
         | 
| 78 | 
            +
                      records.each do |record|
         | 
| 79 | 
            +
                        row = io.to_row(record, block)
         | 
| 80 | 
            +
                        io << row if row
         | 
| 81 | 
            +
                      end
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    io.close
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def csv_import(file, options = {}, &block)
         | 
| 88 | 
            +
                    io = CsvIO.new(:read, file, options[:columns] || _csv_columns_, options)
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    io.each do |row|
         | 
| 91 | 
            +
                      attrs = io.to_attrs(row, block)
         | 
| 92 | 
            +
                      create(attrs) if attrs
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
            end
         | 
| @@ -0,0 +1,67 @@ | |
| 1 | 
            +
            require 'forwardable'
         | 
| 2 | 
            +
            require 'csv'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Mongokit
         | 
| 5 | 
            +
              class CsvIO
         | 
| 6 | 
            +
                attr_reader :csv, :column_mapping, :columns, :options
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                extend Forwardable
         | 
| 9 | 
            +
                def_delegators :@csv, :<<, :readline, :close, :each
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(operation, file, columns, options = {})
         | 
| 12 | 
            +
                  @options = options
         | 
| 13 | 
            +
                  @column_mapping = build_column_mapping(columns)
         | 
| 14 | 
            +
                  @columns = @column_mapping.keys.map(&:to_sym)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  if operation == :write
         | 
| 17 | 
            +
                    @csv = CSV.open(file, 'wb')
         | 
| 18 | 
            +
                    write_headers
         | 
| 19 | 
            +
                  else
         | 
| 20 | 
            +
                    @csv = CSV.open(file)
         | 
| 21 | 
            +
                    @csv.readline if options[:headers]
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def build_column_mapping(columns)
         | 
| 26 | 
            +
                  if columns.is_a?(Array)
         | 
| 27 | 
            +
                    columns.zip((0..columns.length).to_a).to_h.reject{|k| k.nil? }
         | 
| 28 | 
            +
                  else
         | 
| 29 | 
            +
                    columns.sort_by{|_, pos| pos }.to_h
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def write_headers
         | 
| 34 | 
            +
                  return if options[:headers].nil?
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  if options[:headers] === true
         | 
| 37 | 
            +
                    csv << column_mapping.map { |f, _|  f.to_s.titleize }
         | 
| 38 | 
            +
                  else
         | 
| 39 | 
            +
                    csv << options[:headers]
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def to_attrs(row, block)
         | 
| 44 | 
            +
                  attrs = column_mapping.inject({}) do |r, (f, pos)|
         | 
| 45 | 
            +
                    r[f] = row[pos]
         | 
| 46 | 
            +
                    r
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  if block
         | 
| 50 | 
            +
                    return false if block.call(row, attrs) == false
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  attrs
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def to_row(record, block)
         | 
| 57 | 
            +
                  row = CSV::Row.new(columns, columns.map {|f| record[f] })
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  if block
         | 
| 60 | 
            +
                    return false if block.call(row, record) == false
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  row
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              module MongoidDocument
         | 
| 3 | 
            +
                def mongokit(*modules)
         | 
| 4 | 
            +
                  modules = modules.map(&:to_sym).uniq
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  modules.each do |module_name|
         | 
| 7 | 
            +
                    const_name = Mongokit::MODULE_NAMES[module_name]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    if const_name
         | 
| 10 | 
            +
                      self.send :include, Mongokit.const_get(const_name)
         | 
| 11 | 
            +
                    else
         | 
| 12 | 
            +
                      raise MongokitError, "#{module_name} not existing in mongokit"
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Mongoid::Document::ClassMethods.send :include, Mongokit::MongoidDocument
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              #
         | 
| 3 | 
            +
              # == Example
         | 
| 4 | 
            +
              #   Order.in_batches do |orders|
         | 
| 5 | 
            +
              #     orders.each do |order|
         | 
| 6 | 
            +
              #       puts order.items
         | 
| 7 | 
            +
              #     end
         | 
| 8 | 
            +
              #   end
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              #   Order.in_batches(batch_size: 100, start: 50) do |orders|
         | 
| 11 | 
            +
              #     ...
         | 
| 12 | 
            +
              #   end
         | 
| 13 | 
            +
              #
         | 
| 14 | 
            +
              #   Order.where(:created_at.gt => Time.now.yesterday).in_batches do |orders|
         | 
| 15 | 
            +
              #     ...
         | 
| 16 | 
            +
              #   end
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              module FindInBatch
         | 
| 19 | 
            +
                def in_batches(options = {})
         | 
| 20 | 
            +
                  criteria = self
         | 
| 21 | 
            +
                  start = options[:start]
         | 
| 22 | 
            +
                  batch_size = options[:batch_size] || 1000
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  criteria = criteria.limit(batch_size)
         | 
| 25 | 
            +
                  records = start ? criteria.offset(start).to_a : criteria.to_a
         | 
| 26 | 
            +
                  current_offset = start.to_i
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  while records.any?
         | 
| 29 | 
            +
                    records_size = records.size
         | 
| 30 | 
            +
                    current_offset += records_size
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    yield records
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    break if records_size < batch_size
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    records = criteria.offset(current_offset).to_a
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            Mongoid::Document::ClassMethods.send :include, Mongokit::FindInBatch
         | 
| 43 | 
            +
            Mongoid::Criteria.send :include, Mongokit::FindInBatch
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              module ModelHelpers
         | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                # == Example
         | 
| 7 | 
            +
                #
         | 
| 8 | 
            +
                #   class Game
         | 
| 9 | 
            +
                #     include Mongoid::Document
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                #     mongokit :model_helpers
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                #     field :format, type: String
         | 
| 14 | 
            +
                #     field :category, type: Integer
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                #     multi_fields :city, { venue: 'Mumbai' }, :country  # Default string type
         | 
| 17 | 
            +
                #     multi_fields :start_time, :end_time, DateTime
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                #     field_with_validation(:team_type, inclusion: { in: %w(t20 odi test) })
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                #     boolean_methods(:format, %w(t20 odi test), { postfix: 'match' } )
         | 
| 22 | 
            +
                #   end
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                #   game = Game.new(format: 't20')
         | 
| 25 | 
            +
                #   game.t20_match?  # true
         | 
| 26 | 
            +
                #   game.odi_match?  # false
         | 
| 27 | 
            +
                #
         | 
| 28 | 
            +
                module ClassMethods
         | 
| 29 | 
            +
                  def boolean_methods(field_name, values, options = {})
         | 
| 30 | 
            +
                    values = values.zip(values).to_h if values.is_a?(Array)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    values.each do |f, v|
         | 
| 33 | 
            +
                      method_name = [
         | 
| 34 | 
            +
                        options[:prefix],
         | 
| 35 | 
            +
                        f,
         | 
| 36 | 
            +
                        options[:postfix],
         | 
| 37 | 
            +
                      ].compact.join('_')
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      define_method "#{method_name}?" do
         | 
| 40 | 
            +
                        v == self[field_name]
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def multi_fields(*args)
         | 
| 46 | 
            +
                    type = args.pop
         | 
| 47 | 
            +
                    fields = args
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    unless type.is_a?(Class)
         | 
| 50 | 
            +
                      fields << type
         | 
| 51 | 
            +
                      type = String
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    fields.each do |f|
         | 
| 55 | 
            +
                      if f.is_a?(Hash)
         | 
| 56 | 
            +
                        f, default_value = f.flatten
         | 
| 57 | 
            +
                      end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                      field f, type: type, default: default_value
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  def field_with_validation(field_name, options = {})
         | 
| 64 | 
            +
                    field field_name, {
         | 
| 65 | 
            +
                      type: options.delete(:type) || String,
         | 
| 66 | 
            +
                      default: options.delete(:default)
         | 
| 67 | 
            +
                    }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    if options.any?
         | 
| 70 | 
            +
                      validates field_name, options
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              module Models
         | 
| 3 | 
            +
                class AutoIncrementCounter
         | 
| 4 | 
            +
                  include Mongoid::Document
         | 
| 5 | 
            +
                  include Mongoid::Timestamps
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  store_in(collection: 'auto_increment_counters')
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  field :counter_model_name, type: String
         | 
| 10 | 
            +
                  field :counter_field, type: String
         | 
| 11 | 
            +
                  field :counter, type: Integer, default: 0
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  index({ counter_model_name: 1, counter_field: 1 }, { unique: true })
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def self.find_or_create_with_seed(options)
         | 
| 16 | 
            +
                    record = find_or_initialize_by({
         | 
| 17 | 
            +
                      counter_model_name: options[:model].collection_name,
         | 
| 18 | 
            +
                      counter_field: options[:attribute]
         | 
| 19 | 
            +
                    })
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    if record.new_record?
         | 
| 22 | 
            +
                      record.counter = options[:start] > 0 ? options[:start] - 1 : options[:start]
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    record.save
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def self.current_counter(options)
         | 
| 29 | 
            +
                    record = Models::AutoIncrementCounter.find_by({
         | 
| 30 | 
            +
                      counter_model_name: options[:model].collection_name,
         | 
| 31 | 
            +
                      counter_field: options[:attribute]
         | 
| 32 | 
            +
                    })
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    return nil if record.nil?
         | 
| 35 | 
            +
                    return record.counter if options[:pattern].nil?
         | 
| 36 | 
            +
                    return Formater.new.format(record.counter, options)
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            require 'securerandom'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mongokit
         | 
| 4 | 
            +
              module SecureToken
         | 
| 5 | 
            +
                extend ActiveSupport::Concern
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                module ClassMethods
         | 
| 8 | 
            +
                  # == Example
         | 
| 9 | 
            +
                  #
         | 
| 10 | 
            +
                  #   class User
         | 
| 11 | 
            +
                  #     include Mongoid::Document
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  #     mongokit :secure_token
         | 
| 14 | 
            +
                  #
         | 
| 15 | 
            +
                  #     has_secure_token :auth_token
         | 
| 16 | 
            +
                  #     # has_secure_token :auth_token, token_length: 20
         | 
| 17 | 
            +
                  #
         | 
| 18 | 
            +
                  #     # multiple tokens
         | 
| 19 | 
            +
                  #     # has_secure_token :public_key
         | 
| 20 | 
            +
                  #     # has_secure_token :private_key, token_length: 20
         | 
| 21 | 
            +
                  #   end
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  #   user = User.new
         | 
| 24 | 
            +
                  #   user.save
         | 
| 25 | 
            +
                  #   user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7"
         | 
| 26 | 
            +
                  #   user.regenerate_auth_token! # => true
         | 
| 27 | 
            +
                  #
         | 
| 28 | 
            +
                  def has_secure_token(attribute, options = {})
         | 
| 29 | 
            +
                    field(attribute, type: String)
         | 
| 30 | 
            +
                    index({ attribute => 1 }, { unique: true })
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    @_st_options_ ||= {}
         | 
| 33 | 
            +
                    @_st_options_[attribute] =  (options || {}).tap do |o|
         | 
| 34 | 
            +
                      o[:random_string] = (('0'..'9').to_a  + ('A'..'Z').to_a + ('a'..'z').to_a - ['0', 'O', 'I', 'l']).sample(4).join
         | 
| 35 | 
            +
                      o[:token_length] ||= 16
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    before_create do |doc|
         | 
| 39 | 
            +
                      doc[attribute] = doc.class.generate_unique_secure_token(attribute)
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 43 | 
            +
                      def regenerate_#{attribute}!
         | 
| 44 | 
            +
                        update_attributes(#{attribute}: self.class.generate_unique_secure_token(:#{attribute}))
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    RUBY
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 49 | 
            +
                      def find_by_#{attribute}(token)
         | 
| 50 | 
            +
                        where(#{attribute}: token).first
         | 
| 51 | 
            +
                      end
         | 
| 52 | 
            +
                    RUBY
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def generate_unique_secure_token(attribute)
         | 
| 56 | 
            +
                    options = @_st_options_[attribute]
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    loop do
         | 
| 59 | 
            +
                      token = SecureRandom.base64(options[:token_length]).tr('0+/=', options[:random_string])
         | 
| 60 | 
            +
                      break token unless where(attribute => token).exists?
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            module Mongokit
         | 
| 2 | 
            +
              class Options
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                CRITERIAS = [:only, :except, :add, :replace]
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(options = {})
         | 
| 7 | 
            +
                  @options = options
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def all
         | 
| 11 | 
            +
                  @options
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def put(name, values)
         | 
| 15 | 
            +
                  @options[name] = values
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def get(name, field = nil)
         | 
| 19 | 
            +
                  field ? @options[name][field] : @options[name]
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                class << self
         | 
| 23 | 
            +
                  def only(fields, options)
         | 
| 24 | 
            +
                    fields = fields.select{ |f, _| options[:only].include?(f) } if options[:only]
         | 
| 25 | 
            +
                    fields
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def except(fields, options)
         | 
| 29 | 
            +
                    fields = fields.reject{ |f, _| options[:except].include?(f) } if options[:except]
         | 
| 30 | 
            +
                    fields
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def add(fields, options)
         | 
| 34 | 
            +
                    return unless options[:add]
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    fields.is_a?(Hash) ? fields.merge(options[:add]) : fields.concat(options[:add])
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def replace(fields, options)
         | 
| 40 | 
            +
                    options[:replace].each { |old_f, new_f| fields[new_f] = fields.delete(old_f) } if options[:replace]
         | 
| 41 | 
            +
                    fields
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  def process(fields, options, criterias = nil)
         | 
| 45 | 
            +
                    criterias = options.keys unless criterias
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    criterias.each do |c|
         | 
| 48 | 
            +
                      fields = send(c, fields, options) if CRITERIAS.include?(c)
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    fields
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                # Used for common options store.
         | 
| 56 | 
            +
                module Store
         | 
| 57 | 
            +
                  def mk_options
         | 
| 58 | 
            +
                    @mk_options ||= Options.new
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            require 'yaml'
         | 
| 2 | 
            +
            require 'pathname'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module YamlStore
         | 
| 5 | 
            +
              module_function
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              @@store = {}
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def store
         | 
| 10 | 
            +
                @@store
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def load(*files)
         | 
| 14 | 
            +
                files.each do |f|
         | 
| 15 | 
            +
                  yaml = Pathname.new(f)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  unless yaml.exist?
         | 
| 18 | 
            +
                    raise "File not found #{f}"
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  key = yaml.basename.to_s.gsub(yaml.extname, '')
         | 
| 22 | 
            +
                  @@store[key.to_sym] = read_yaml(yaml)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 25 | 
            +
                    def #{key}
         | 
| 26 | 
            +
                      store[:#{key}]
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  RUBY
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def get(name, key = nil)
         | 
| 33 | 
            +
                values = @@store[name]
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                return nil unless values
         | 
| 36 | 
            +
                return key ? values[key] : values
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def read_yaml(file)
         | 
| 40 | 
            +
                yml = YAML.load_file(file)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                if defined?(Rails)
         | 
| 43 | 
            +
                  yml = yml[Rails.evn] || yml[Rails.evn.to_sym]
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                yml
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         | 
    
        data/mongokit.gemspec
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'mongokit/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "mongokit"
         | 
| 8 | 
            +
              spec.version       = Mongokit::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Jiren"]
         | 
| 10 | 
            +
              spec.email         = ["jirenpatel@gmail.com"]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              spec.summary       = %q{Helpers for mongoid i.e auto increment fields, search index}
         | 
| 13 | 
            +
              spec.description   = %q{Helpers for mongoid i.e auto increment fields, search index}
         | 
| 14 | 
            +
              spec.homepage      = "http://github.com/jiren/mongokit"
         | 
| 15 | 
            +
              spec.license       = "MIT"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|examples)/}) }
         | 
| 18 | 
            +
              spec.bindir        = "exe"
         | 
| 19 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 20 | 
            +
              spec.require_paths = ["lib"]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              spec.add_development_dependency "bundler", "~> 1.9"
         | 
| 23 | 
            +
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 24 | 
            +
              spec.add_development_dependency "database_cleaner", "~> 1.2.0"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              spec.add_dependency("mongoid", "~> 4.0.0")
         | 
| 27 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,127 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: mongokit
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Jiren
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2015-06-12 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: bundler
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '1.9'
         | 
| 20 | 
            +
              type: :development
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '1.9'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rake
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '10.0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '10.0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: database_cleaner
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: 1.2.0
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: 1.2.0
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: mongoid
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - "~>"
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: 4.0.0
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - "~>"
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: 4.0.0
         | 
| 69 | 
            +
            description: Helpers for mongoid i.e auto increment fields, search index
         | 
| 70 | 
            +
            email:
         | 
| 71 | 
            +
            - jirenpatel@gmail.com
         | 
| 72 | 
            +
            executables: []
         | 
| 73 | 
            +
            extensions: []
         | 
| 74 | 
            +
            extra_rdoc_files: []
         | 
| 75 | 
            +
            files:
         | 
| 76 | 
            +
            - ".gitignore"
         | 
| 77 | 
            +
            - ".rspec"
         | 
| 78 | 
            +
            - ".travis.yml"
         | 
| 79 | 
            +
            - CODE_OF_CONDUCT.md
         | 
| 80 | 
            +
            - Gemfile
         | 
| 81 | 
            +
            - LICENSE.txt
         | 
| 82 | 
            +
            - README.md
         | 
| 83 | 
            +
            - Rakefile
         | 
| 84 | 
            +
            - bin/console
         | 
| 85 | 
            +
            - bin/setup
         | 
| 86 | 
            +
            - lib/mongokit.rb
         | 
| 87 | 
            +
            - lib/mongokit/address.rb
         | 
| 88 | 
            +
            - lib/mongokit/auto_increment.rb
         | 
| 89 | 
            +
            - lib/mongokit/auto_increment/counter.rb
         | 
| 90 | 
            +
            - lib/mongokit/auto_increment/formater.rb
         | 
| 91 | 
            +
            - lib/mongokit/csv_transformer.rb
         | 
| 92 | 
            +
            - lib/mongokit/csv_transformer/csv_io.rb
         | 
| 93 | 
            +
            - lib/mongokit/extensions/mongoid_document.rb
         | 
| 94 | 
            +
            - lib/mongokit/find_in_batch.rb
         | 
| 95 | 
            +
            - lib/mongokit/model_helpers.rb
         | 
| 96 | 
            +
            - lib/mongokit/models/auto_increment_counter.rb
         | 
| 97 | 
            +
            - lib/mongokit/secure_token.rb
         | 
| 98 | 
            +
            - lib/mongokit/utils/options.rb
         | 
| 99 | 
            +
            - lib/mongokit/version.rb
         | 
| 100 | 
            +
            - lib/mongokit/yaml_store.rb
         | 
| 101 | 
            +
            - mongokit.gemspec
         | 
| 102 | 
            +
            homepage: http://github.com/jiren/mongokit
         | 
| 103 | 
            +
            licenses:
         | 
| 104 | 
            +
            - MIT
         | 
| 105 | 
            +
            metadata: {}
         | 
| 106 | 
            +
            post_install_message: 
         | 
| 107 | 
            +
            rdoc_options: []
         | 
| 108 | 
            +
            require_paths:
         | 
| 109 | 
            +
            - lib
         | 
| 110 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 111 | 
            +
              requirements:
         | 
| 112 | 
            +
              - - ">="
         | 
| 113 | 
            +
                - !ruby/object:Gem::Version
         | 
| 114 | 
            +
                  version: '0'
         | 
| 115 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 116 | 
            +
              requirements:
         | 
| 117 | 
            +
              - - ">="
         | 
| 118 | 
            +
                - !ruby/object:Gem::Version
         | 
| 119 | 
            +
                  version: '0'
         | 
| 120 | 
            +
            requirements: []
         | 
| 121 | 
            +
            rubyforge_project: 
         | 
| 122 | 
            +
            rubygems_version: 2.4.5
         | 
| 123 | 
            +
            signing_key: 
         | 
| 124 | 
            +
            specification_version: 4
         | 
| 125 | 
            +
            summary: Helpers for mongoid i.e auto increment fields, search index
         | 
| 126 | 
            +
            test_files: []
         | 
| 127 | 
            +
            has_rdoc: 
         |