findable 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,8 @@ module Findable
2
2
  class Configuration
3
3
  VALID_OPTIONS = [
4
4
  :redis_options,
5
- :seed_file
5
+ :seed_dir,
6
+ :seed_file,
6
7
  ].freeze
7
8
 
8
9
  attr_accessor *VALID_OPTIONS
@@ -26,6 +27,7 @@ module Findable
26
27
 
27
28
  def reset
28
29
  self.redis_options = nil
30
+ self.seed_dir = defined?(Rails) ? Rails.root.join("db", "findable_seeds") : nil
29
31
  self.seed_file = defined?(Rails) ? Rails.root.join("db", "findable_seeds.rb") : nil
30
32
  end
31
33
 
@@ -1,10 +1,16 @@
1
1
  module Findable
2
2
  class FindableError < StandardError; end
3
- class RecordNotFound < FindableError; end
3
+
4
+ class RecordNotFound < FindableError
5
+ def initialize(model, params)
6
+ params.symbolize_keys! if params.is_a?(Hash)
7
+ super("Couldn't find #{model.model_name.name} with #{params.inspect}")
8
+ end
9
+ end
4
10
 
5
11
  class ModelNotFound < FindableError
6
12
  def initialize(model_name)
7
- super("#{model_name} not found!")
13
+ super("#{model_name} not found.")
8
14
  end
9
15
  end
10
16
  end
@@ -0,0 +1,91 @@
1
+ require "findable/query/connection"
2
+ require "findable/query/namespace"
3
+
4
+ module Findable
5
+ class Query
6
+ include Connection
7
+ include Namespace
8
+
9
+ def data
10
+ redis.hvals(data_key)
11
+ end
12
+
13
+ def ids
14
+ redis.hkeys(data_key).map(&:to_i)
15
+ end
16
+
17
+ def count
18
+ redis.hlen(data_key)
19
+ end
20
+
21
+ def find_by_ids(ids)
22
+ redis.hmget(data_key, *Array(ids))
23
+ end
24
+
25
+ def exists?(id)
26
+ redis.hexists(data_key, id)
27
+ end
28
+
29
+ def insert(hash)
30
+ transaction do
31
+ hash[:id] = auto_incremented_id(hash[:id])
32
+ redis.hset(data_key, hash[:id], Oj.dump(hash))
33
+ end
34
+ hash
35
+ end
36
+
37
+ def import(hashes)
38
+ transaction do
39
+ auto_incremented = hashes.each_with_object([]) do |hash, obj|
40
+ hash["id"] = auto_incremented_id(hash["id"])
41
+ obj << hash["id"]
42
+ obj << Oj.dump(hash)
43
+ end
44
+ redis.hmset(data_key, *auto_incremented)
45
+ end
46
+ end
47
+
48
+ def delete(id)
49
+ redis.hdel data_key, id
50
+ end
51
+
52
+ def delete_all
53
+ redis.multi do
54
+ [data_key, info_key].each {|key| redis.del(key) }
55
+ end
56
+ end
57
+
58
+ def transaction
59
+ raise ArgumentError, "Require block" unless block_given?
60
+ if Thread.current[thread_key]
61
+ yield
62
+ else
63
+ begin
64
+ Thread.current[thread_key] = true
65
+ Redis::Lock.new(lock_key).lock do
66
+ yield
67
+ end
68
+ rescue Redis::Lock::LockTimeout
69
+ raise
70
+ ensure
71
+ Thread.current[thread_key] = nil
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+ def auto_incremented_id(id)
78
+ if id.present?
79
+ current = redis.hget(info_key, AUTO_INCREMENT_KEY).to_i
80
+ id = id.to_i
81
+ if id > current
82
+ redis.hset(info_key, AUTO_INCREMENT_KEY, id)
83
+ end
84
+ id
85
+ else
86
+ redis.hincrby(info_key, AUTO_INCREMENT_KEY, 1)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
@@ -0,0 +1,26 @@
1
+ module Findable
2
+ class Query
3
+ module Connection
4
+ # Returns current connection or generate connection.
5
+ # @return [Redis] Redis connection
6
+ def redis
7
+ @_redis ||= generate_redis_connection!
8
+ end
9
+
10
+ private
11
+ # Generate connection with redis options or default connection.
12
+ # @return [Redis] Redis connection
13
+ def generate_redis_connection!
14
+ redis_options ? Redis.new(*redis_options) : Redis.current
15
+ end
16
+
17
+ # Returns redis options from configuration.
18
+ # @return [Hash] Redis options
19
+ # @return [nil] No Redis options
20
+ def redis_options
21
+ Findable.config.redis_options.presence
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,34 @@
1
+ module Findable
2
+ class Query
3
+ module Namespace
4
+ PREFIX = "findable".freeze
5
+ KEY_NAMES = %i(info data lock index).freeze
6
+ AUTO_INCREMENT_KEY = :auto_increment
7
+
8
+ def initialize(model)
9
+ @_model = model
10
+ end
11
+
12
+ KEY_NAMES.each do |key|
13
+ define_method([key, "key"].join("_")) { namespaces[key] }
14
+ end
15
+
16
+ def thread_key
17
+ [PREFIX, basename].join("_")
18
+ end
19
+
20
+ private
21
+ def basename
22
+ @_model.model_name.plural
23
+ end
24
+
25
+ # @return [Hash] namespaces
26
+ def namespaces
27
+ @_namespaces ||= KEY_NAMES.each_with_object({}) {|key, obj|
28
+ obj[key] = [PREFIX, basename, key].join(":")
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -2,7 +2,7 @@ module Findable
2
2
  class Railtie < ::Rails::Railtie
3
3
  initializer "findable" do
4
4
  ActiveSupport.on_load(:active_record) do
5
- ::ActiveRecord::Base.send(:extend, Findable::Association)
5
+ require "findable/associations/active_record_ext"
6
6
  end
7
7
  end
8
8
 
data/lib/findable/seed.rb CHANGED
@@ -1,61 +1,57 @@
1
1
  module Findable
2
2
  class Seed
3
- attr_reader :full_path, :namespaced, :ext
3
+ class << self
4
+ def target_files(seed_dir: nil, seed_files: nil)
5
+ target_dir = pathname(seed_dir) || Findable.config.seed_dir
6
+ raise ArgumentError unless target_dir
7
+ Pathname.glob(target_dir.join("**", "*")).map {|full_path|
8
+ new(full_path, target_dir)
9
+ }.select {|seed|
10
+ seed_files.present? ? seed_files.include?(seed.basename) : true
11
+ }
12
+ end
4
13
 
5
- def initialize(path, seed_dir)
6
- @_seed_dir = seed_dir
7
- self.full_path = path
14
+ def pathname(path)
15
+ case path
16
+ when Pathname then path
17
+ when String then Pathname.new(path)
18
+ else nil
19
+ end
20
+ end
8
21
  end
9
22
 
10
- def full_path=(path)
11
- @full_path = path
12
- _path = path.gsub(@_seed_dir, "")
13
- @namespaced = /^\// =~ _path ? _path.from(1) : _path
14
- @ext = @namespaced[/^.*(?<ext>\.[^\.]+)$/, :ext] || (raise ArgumentError)
23
+ def initialize(full_path, seed_dir)
24
+ @_full_path = full_path
25
+ @_seed_dir = seed_dir
15
26
  end
16
27
 
17
- def base_name
18
- @_base ||= @namespaced.sub(@ext, "")
28
+ def basename
29
+ @_basename ||= @_full_path.basename(".*").to_s
19
30
  end
20
31
 
21
32
  def model
22
- base_name.split("/").reverse.map.with_index {|n,i|
23
- i.zero? ? n.singularize : n
24
- }.reverse.map(&:camelize).join("::").constantize
25
- end
26
-
27
- def load_file
28
- case @ext
29
- when ".yml"
30
- YAML.load_file(@full_path).values
31
- else
32
- raise UnexpectedFormat
33
- end
33
+ @_model ||= from_seed_dir(without_ext(@_full_path)).to_s.classify.constantize
34
34
  end
35
35
 
36
36
  def bootstrap!
37
- model.transaction do
37
+ model.query.transaction do
38
38
  model.delete_all
39
- records = load_file.map {|data| model.new(data) }
40
- model.import records
39
+ model.query.import YAML.load_file(@_full_path).values
41
40
  end
42
41
  end
43
42
 
44
- class << self
45
- def target_files(seed_dir, tables = nil)
46
- Dir.glob(patterns(seed_dir)).map {|full_path|
47
- Seed.new(full_path, seed_dir)
48
- }.select {|seed|
49
- tables ? tables.include?(seed.base_name) : true
50
- }
43
+ private
44
+ def pathname(path)
45
+ self.class.pathname(path)
51
46
  end
52
47
 
53
- def patterns(seed_dir)
54
- %w(yml).map {|format|
55
- Rails.root.join("#{seed_dir}/**/*.#{format}").to_s
56
- }
48
+ def without_ext(path)
49
+ pathname(path).dirname.join(pathname(path).basename(".*"))
50
+ end
51
+
52
+ def from_seed_dir(path)
53
+ pathname(path).relative_path_from(@_seed_dir)
57
54
  end
58
- end
59
55
  end
60
56
  end
61
57
 
@@ -1,4 +1,4 @@
1
1
  module Findable
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
4
4
 
@@ -3,6 +3,11 @@ module Findable
3
3
  class InstallGenerator < ::Rails::Generators::Base
4
4
  source_root File.expand_path(File.join(File.dirname(__FILE__), "templates"))
5
5
 
6
+ desc "Create seed_dir of Findable."
7
+ def create_seed_dir
8
+ create_file File.join("db", "findable_seeds", ".keep")
9
+ end
10
+
6
11
  desc "Install Findable files"
7
12
  def install_findable_files
8
13
  template "seeds.rb", "db/findable_seeds.rb"
@@ -2,7 +2,10 @@ Findable.configure do |config|
2
2
  # Redis connection setting. (default: `Redis.current`)
3
3
  # config.redis_options = {host: "localhost", port: 6379, db: 2}
4
4
 
5
- # Seed file of Findable
6
- # config.seed_file = Rails.root.join("db", "findable_seeds.rb")
5
+ # Directory of stored seed files.
6
+ config.seed_dir = Rails.root.join("db", "findable_seeds")
7
+
8
+ # Seed file of Findable.
9
+ config.seed_file = Rails.root.join("db", "findable_seeds.rb")
7
10
  end
8
11
 
@@ -3,9 +3,6 @@
3
3
  # Require seed support module
4
4
  require "findable/seed"
5
5
 
6
- # Path to the reading of the seed.
7
- seed_dir = File.expand_path("../findable_seeds", __FILE__)
8
-
9
6
  # Target seed files.
10
7
  # Run all in the case of `nil`.
11
8
  # Example of if you want to run some only.
@@ -13,5 +10,5 @@ seed_dir = File.expand_path("../findable_seeds", __FILE__)
13
10
  seed_files = nil
14
11
 
15
12
  # Execute
16
- Findable::Seed.target_files(seed_dir, seed_files).each {|seed| seed.bootstrap! }
13
+ Findable::Seed.target_files(seed_files: seed_files).each {|seed| seed.bootstrap! }
17
14
 
data/spec/spec_helper.rb CHANGED
@@ -1,19 +1,7 @@
1
- require "simplecov"
1
+ require "findable"
2
2
  require "coveralls"
3
3
  Coveralls.wear!
4
4
 
5
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
- SimpleCov::Formatter::HTMLFormatter,
7
- Coveralls::SimpleCov::Formatter
8
- ]
9
-
10
- SimpleCov.start do
11
- add_filter "spec"
12
- add_filter ".bundle"
13
- end
14
-
15
- require "findable"
16
-
17
5
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
18
6
 
19
7
  RSpec.configure do |config|
@@ -0,0 +1,2 @@
1
+ Redis.current.flushdb
2
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: findable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - i2bskn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-14 00:00:00.000000000 Z
11
+ date: 2015-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: redis
42
+ name: redis-objects
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: simplecov
112
+ name: pry
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -152,16 +152,17 @@ files:
152
152
  - Rakefile
153
153
  - findable.gemspec
154
154
  - lib/findable.rb
155
- - lib/findable/association.rb
155
+ - lib/findable/associations.rb
156
+ - lib/findable/associations/active_record_ext.rb
157
+ - lib/findable/associations/utils.rb
156
158
  - lib/findable/base.rb
157
159
  - lib/findable/configuration.rb
158
- - lib/findable/connection.rb
159
160
  - lib/findable/errors.rb
160
- - lib/findable/namespace.rb
161
+ - lib/findable/query.rb
162
+ - lib/findable/query/connection.rb
163
+ - lib/findable/query/namespace.rb
161
164
  - lib/findable/railtie.rb
162
- - lib/findable/recordable.rb
163
165
  - lib/findable/seed.rb
164
- - lib/findable/serializer.rb
165
166
  - lib/findable/version.rb
166
167
  - lib/generators/findable/install_generator.rb
167
168
  - lib/generators/findable/templates/findable.rb
@@ -172,6 +173,7 @@ files:
172
173
  - spec/findable/configuration_spec.rb
173
174
  - spec/spec_helper.rb
174
175
  - spec/support/.keep
176
+ - spec/support/initialize_redis.rb
175
177
  homepage: https://github.com/i2bskn/findable
176
178
  licenses:
177
179
  - MIT
@@ -192,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
194
  version: '0'
193
195
  requirements: []
194
196
  rubyforge_project:
195
- rubygems_version: 2.2.2
197
+ rubygems_version: 2.4.5
196
198
  signing_key:
197
199
  specification_version: 4
198
200
  summary: Redis wrapper with API like ActiveRecord.
@@ -202,3 +204,4 @@ test_files:
202
204
  - spec/findable/configuration_spec.rb
203
205
  - spec/spec_helper.rb
204
206
  - spec/support/.keep
207
+ - spec/support/initialize_redis.rb