local_model 0.1.12 → 0.1.14

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23ec22d2650b17792c2a03dff88d9dffbcedd78b08ebd05afd057fd124d0476a
4
- data.tar.gz: 8c89b6eaf25891cb05c3692785d9e88979372be6078ea465d080e9fbd9a7f330
3
+ metadata.gz: 52fd36165c3ec49f275a899b9c687e99e91942c64d603542f5295dfbd6b4070a
4
+ data.tar.gz: 26992202b57f21466187744566b20f1be8a2701d15a3cb6975dcd4f5f389d902
5
5
  SHA512:
6
- metadata.gz: 6b770b1003097729755a6a63df94b909c58eb2c39ae64f398db5ff64083b2846307b173d8da3bd3533efa30ba4dce9dce2170f69ac3e6cc61d886d2b4cf08d5c
7
- data.tar.gz: 405d6229dbb39b63e8fc5b9dd01d0e3dadaedf06907519f85a411a0d0547c7a1c12d6b1e7528d11f50a6d2e1cfe79f13526f5dcd6e919e1e91125ec9c03290b5
6
+ metadata.gz: 34dfb6506d823c13ecbe82869a7a60d3047e3842df78af576e7cf8b463422736bd95e103ef38b5ce57373e03f3a9d957ba83235984caec258aa593b348206d39
7
+ data.tar.gz: 989578a3bab8d8bb7d60fc1556b2f28c0c0e718f9c2d0054b178c1e2a460857fba0108198ce9ed13c5c0b7adec08a9f3ce21eaf8e3cb46bca9d0f871f754a83f
data/Gemfile CHANGED
@@ -9,3 +9,5 @@ gemspec
9
9
  gem "pry", "~> 0.14.1", group: :development
10
10
 
11
11
  gem "irb", "~> 1.3"
12
+
13
+ gem "thor", "~> 1.2"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- local_model (0.1.10)
4
+ local_model (0.1.13)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -31,6 +31,7 @@ GEM
31
31
  diff-lcs (>= 1.2.0, < 2.0)
32
32
  rspec-support (~> 3.10.0)
33
33
  rspec-support (3.10.2)
34
+ thor (1.2.1)
34
35
 
35
36
  PLATFORMS
36
37
  x86_64-linux
@@ -42,6 +43,7 @@ DEPENDENCIES
42
43
  pry (~> 0.14.1)
43
44
  rake (~> 13.0)
44
45
  rspec (~> 3.10)
46
+ thor (~> 1.2)
45
47
 
46
48
  BUNDLED WITH
47
- 2.2.17
49
+ 2.3.14
data/README.md CHANGED
@@ -1,9 +1,5 @@
1
1
  # LocalModel
2
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/local_model`. 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
3
  ## Installation
8
4
 
9
5
  Add this line to your application's Gemfile:
@@ -22,6 +18,36 @@ Or install it yourself as:
22
18
 
23
19
  ## Usage
24
20
 
21
+ Use the generator:
22
+
23
+ ```bash
24
+ bundle add local_model
25
+ ```
26
+ ```
27
+ bundle exec local_model --namespace DesiredNamespace
28
+ ```
29
+ Note: `--namespace` is optional and will default to `InMemory`
30
+ This creates a rails initializer which sets some config options,
31
+ and a `DataAccessor` class which you can use to switch between your `LocalModel` objects and your `ActiveRecord` objects.
32
+
33
+ Recommend adding:
34
+
35
+ `config/application.rb`
36
+ ```ruby
37
+ config.autoload_paths << config.root.join('lib')
38
+ ```
39
+
40
+ so you get all of these files.
41
+
42
+ You can set an environment variable `USE_LOCAL_MODELS` to `true` or `false` to globally decide what to use.
43
+
44
+
45
+ You also now can use a rake task to generate your `LocalModel` models:
46
+ `rake local_model:create_model\[User\]`
47
+ (The `\`s should only be necessary in zsh, not bash)
48
+
49
+ OR, you can manually:
50
+
25
51
  Create your schema:
26
52
 
27
53
  ```rb
data/Rakefile CHANGED
@@ -5,9 +5,12 @@ RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task :default => :spec
7
7
 
8
- desc "run a console"
9
- task :console do
10
- require 'pry'
8
+ desc "environment"
9
+ task :environment do
11
10
  require_relative './lib/local_model.rb'
12
- binding.pry
11
+ end
12
+
13
+ desc "run file generator"
14
+ task :generate => :environment do
15
+ LocalModel::Generator.new.invoke_all
13
16
  end
data/bin/local_model ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'local_model'
4
+
5
+ LocalModel::Generators::Initialize.start
@@ -5,7 +5,8 @@ class LocalModel::FloatAdapter
5
5
  end
6
6
 
7
7
  def self.read(flstr)
8
- flstr =~ /[^0-9\.]/ ? nil : flstr.to_f
8
+ str = flstr.strip
9
+ str =~ /^[+-]?([1-9]\d*|0)(\.\d+)?$/ ? str.to_f : nil
9
10
  end
10
11
 
11
12
  end
@@ -26,7 +26,7 @@ class LocalModel::Collection < Array
26
26
  end
27
27
 
28
28
  def where(**args)
29
- self.filter do |el|
29
+ arr = self.filter do |el|
30
30
  found = true
31
31
  args.each do |k,v|
32
32
  if el.send(k.to_s) != v
@@ -36,6 +36,24 @@ class LocalModel::Collection < Array
36
36
  end
37
37
  found
38
38
  end
39
+ self.class.create_from(
40
+ array: arr,
41
+ for_model: model,
42
+ for_collection_class: nil,
43
+ add_to_collection_proc: ->(a,b) { raise NoMethodError.new("Cannot add to this collection") }
44
+ )
45
+ end
46
+
47
+ def find_by(**args)
48
+ where(**args).first
49
+ end
50
+
51
+ def first
52
+ self[0]
53
+ end
54
+
55
+ def last
56
+ self[-1]
39
57
  end
40
58
 
41
59
  end
@@ -37,6 +37,10 @@ class LocalModel::CSV < LocalModel::Model
37
37
  schema_data
38
38
  end
39
39
 
40
+ self.define_method :schema_defaults do
41
+ builder.defaults
42
+ end
43
+
40
44
  if !File.file?(self.storage_path)
41
45
  CSV.open(self.storage_path, 'wb') do |csv|
42
46
  csv << cols.map(&:to_s)
@@ -63,7 +67,7 @@ class LocalModel::CSV < LocalModel::Model
63
67
  end
64
68
 
65
69
  def self.where(**args)
66
- all_records do |row|
70
+ arr = all_records do |row|
67
71
  found = true
68
72
  args.each do |k,v|
69
73
  if row[k] != v
@@ -73,6 +77,12 @@ class LocalModel::CSV < LocalModel::Model
73
77
  end
74
78
  found
75
79
  end.map{|r| new_from_record(r) }
80
+ LocalModel::Collection.create_from(
81
+ array: arr,
82
+ for_model: self,
83
+ for_collection_class: nil,
84
+ add_to_collection_proc: ->(a,b) { raise NoMethodError.new("Cannot add to this collection") }
85
+ )
76
86
  end
77
87
 
78
88
  def self.find_by(**args)
@@ -108,11 +118,7 @@ class LocalModel::CSV < LocalModel::Model
108
118
  end
109
119
 
110
120
  def self.find(id)
111
- return self.find_by(id: id)
112
- end
113
-
114
- def self.find!(id)
115
- found_record = find(id)
121
+ found_record = self.find_by(id: id)
116
122
  if !found_record
117
123
  raise LocalModel::RecordNotFound.new
118
124
  else
@@ -120,6 +126,14 @@ class LocalModel::CSV < LocalModel::Model
120
126
  end
121
127
  end
122
128
 
129
+ def self.find_or_create_by(**args)
130
+ found_obj = find_by(**args)
131
+ return found_obj if found_obj
132
+ create(**args)
133
+ end
134
+
135
+ # TODO: Move necessary methods to model.rb
136
+
123
137
  def self.create(**args)
124
138
  inst = new(**args)
125
139
  inst.save
@@ -133,6 +147,9 @@ class LocalModel::CSV < LocalModel::Model
133
147
  end
134
148
 
135
149
  def initialize(**args)
150
+ self.schema_defaults.each do |property, value|
151
+ self.send("#{property}=", value)
152
+ end
136
153
  args.each do |k,v|
137
154
  self.send("#{k}=", v)
138
155
  end
@@ -145,7 +162,7 @@ class LocalModel::CSV < LocalModel::Model
145
162
 
146
163
  def reload
147
164
  raise LocalModel::RecordNotFound if !self.id
148
- self.class.find!(self.id)
165
+ self.class.find(self.id)
149
166
  end
150
167
 
151
168
  def destroy
@@ -0,0 +1,32 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+
4
+ module LocalModel
5
+ module Generators
6
+ class Initialize < Thor::Group
7
+ include Thor::Actions
8
+
9
+ class_option :namespace, default: "InMemory"
10
+
11
+ desc 'Create required files'
12
+
13
+ def self.source_root
14
+ File.dirname(__FILE__) + '/../'
15
+ end
16
+
17
+ def create_initializer
18
+ @namespace_classname = options[:namespace]
19
+ template('templates/initializer.erb', 'config/initializers/local_model.rb')
20
+ end
21
+
22
+ def create_data_accessor
23
+ template('templates/data_accessor.erb', 'lib/data_accessor.rb')
24
+ end
25
+
26
+ def create_model_generator
27
+ @class_namespace_snake = LocalModel::Functions.camel_to_snake(@namespace_classname)
28
+ template('templates/generate_model.erb', 'lib/tasks/local_model.rake')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -24,7 +24,6 @@ class LocalModel::PluralizedWords
24
24
  "moves" => "move",
25
25
  "groves" => "grove",
26
26
  "stoves" => "stove",
27
- "beliefs" => "belief"
28
27
  }
29
28
 
30
29
  IRREGULAR_PLURALIZED_WORDS = {
@@ -33,7 +33,7 @@ class LocalModel::Model
33
33
  association_class = Object.const_get(association_class_name)
34
34
  end
35
35
  id = self.send(keyname)
36
- association_class.find(id)
36
+ association_class.find_by(id: id)
37
37
  end
38
38
 
39
39
  define_method "#{association}=" do |association_obj|
@@ -91,7 +91,7 @@ class LocalModel::Model
91
91
  define_method association do
92
92
  association_class = Object.const_get(association_classname)
93
93
  LocalModel::Collection.create_from(
94
- array: self.send(through).map{|through_obj| association_class.find(through_obj.send(belongs_to_id_sym))},
94
+ array: self.send(through).map{|through_obj| association_class.find_by(id: through_obj.send(belongs_to_id_sym))},
95
95
  for_model: self,
96
96
  for_collection_class: association_class,
97
97
  add_to_collection_proc: add_to_collection
@@ -192,37 +192,47 @@ class LocalModel::Model
192
192
  class SchemaBuilder
193
193
 
194
194
  attr_reader :schema
195
+ attr_reader :defaults
195
196
 
196
197
  def initialize(model)
197
198
  @model = model
198
199
  @schema = { id: :integer }
199
200
  @model.attr_accessor :id
201
+ @defaults = {}
200
202
  end
201
203
 
202
- def string(name)
204
+ def set_default(name, default)
205
+ @defaults[name] = default if !default.nil?
206
+ end
207
+
208
+ def string(name, default: nil)
203
209
  @model.attr_accessor name
204
210
  @schema[name] = :string
211
+ set_default(name, default)
205
212
  end
206
213
 
207
- def integer(name)
214
+ def integer(name, default: nil)
208
215
  @model.attr_accessor name
209
216
  @schema[name] = :integer
217
+ set_default(name, default)
210
218
  end
211
219
 
212
- def boolean(name)
220
+ def boolean(name, default: nil)
213
221
  @model.attr_accessor name
214
222
  @schema[name] = :boolean
223
+ set_default(name, default)
215
224
  end
216
225
 
217
- def float(name)
226
+ def float(name, default: nil)
218
227
  @model.attr_accessor name
219
228
  @schema[name] = :float
229
+ set_default(name, default)
220
230
  end
221
231
 
222
- def datetime(name)
232
+ def datetime(name, default: nil)
223
233
  @model.attr_accessor name
224
234
  @schema[name] = :datetime
235
+ set_default(name, default)
225
236
  end
226
-
227
237
  end
228
- end
238
+ end
@@ -0,0 +1,61 @@
1
+ module DataAccessor
2
+ class Base
3
+ class Accessors
4
+ LOCAL = :local
5
+ ACTIVE_RECORD = :active_record
6
+
7
+ NAMESPACES = {
8
+ LOCAL => <%= @namespace_classname %>,
9
+ ACTIVE_RECORD => Object
10
+ }
11
+
12
+ end
13
+
14
+ @@strategy = ENV["USE_LOCAL_MODELS"] ? Accessors::LOCAL : Accessors::ACTIVE_RECORD
15
+ @@exceptions = Set.new([])
16
+
17
+ def self.set_strategy(strat)
18
+ if strat.to_sym == :local
19
+ @@strategy = Accessors::LOCAL
20
+ else
21
+ @@strategy = Accessors::ACTIVE_RECORD
22
+ end
23
+ end
24
+
25
+ def self.klass(klass_name)
26
+ namespace = get_namespace_for(klass_name)
27
+ namespaced_klass_name = "#{namespace}::#{klass_name.to_s}"
28
+ namespaced_klass = Object.const_get(namespaced_klass_name)
29
+ end
30
+ private_class_method :klass
31
+
32
+ def self.get_namespace
33
+ Accessors::NAMESPACES[@@strategy]
34
+ end
35
+ private_class_method :get_namespace
36
+
37
+ def self.get_namespace_for(klass)
38
+ exception_strategy = @@strategy == Accessors::ACTIVE_RECORD ? Accessors::LOCAL : Accessors::ACTIVE_RECORD
39
+ exception_namespace = Accessors::NAMESPACES[exception_strategy]
40
+ if @@exceptions.include?(klass.to_s.to_sym)
41
+ exception_namespace
42
+ else
43
+ get_namespace
44
+ end
45
+ end
46
+ private_class_method :get_namespace_for
47
+
48
+ def self.set_exceptions(exceptions)
49
+ @@exceptions = Set.new(exceptions.map(&:to_sym))
50
+ end
51
+
52
+ # Example - find user
53
+ # def self.find_user(id)
54
+ # ref = klass(:User)
55
+ # ref.find(id)
56
+ # end
57
+ # private_class_method :find_user
58
+
59
+ # MARK: PUBLIC GETTERS
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+
2
+ namespace :local_model do
3
+
4
+ desc "Generate LocalModel model"
5
+ task :create_model, [:klass_name] => :environment do |_t, args|
6
+ klass_name = args[:klass_name]
7
+ model_code = <<~RUBY
8
+ class <%= @namespace_classname %>::#{klass_name} < LocalModel::CSV
9
+ schema do |t|
10
+
11
+ end
12
+ end
13
+ RUBY
14
+
15
+ dir = Rails.root.join('lib', '<%= @class_namespace_snake%>')
16
+ Dir.mkdir(dir) unless File.exists?(dir)
17
+ filename = "#{dir}/#{klass_name.underscore}.rb"
18
+ File.open(filename, 'w') { |f| f.write(model_code) }
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ module <%= @namespace_classname %>
2
+ LocalModel.config do |c|
3
+ c.path = "./tmp/#{ENV['RAILS_ENV'] || 'development'}"
4
+ c.namespace = "<%= @namespace_classname %>"
5
+ c.cleanup_on_start = false
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module LocalModel
2
- VERSION = "0.1.12"
2
+ VERSION = "0.1.14"
3
3
  end
data/lib/local_model.rb CHANGED
@@ -14,6 +14,7 @@ require_relative './local_model/helpers/functions'
14
14
  require_relative './local_model/helpers/pluralized_words'
15
15
  require_relative './local_model/model'
16
16
  require_relative './local_model/csv'
17
+ require_relative './local_model/generators/initialize'
17
18
 
18
19
  module LocalModel
19
20
  class Error < StandardError; end
data/local_model.gemspec CHANGED
@@ -30,8 +30,11 @@ Gem::Specification.new do |spec|
30
30
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
31
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
32
  end
33
- spec.bindir = "exe"
34
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
+ # spec.bindir = "exe"
34
+ spec.bindir = "bin"
35
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
36
+ spec.executables << 'local_model'
37
+ # spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
38
  spec.require_paths = ["lib"]
36
39
 
37
40
  spec.add_development_dependency "bundler", "~> 2.2"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: local_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Shute
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-16 00:00:00.000000000 Z
11
+ date: 2022-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,7 +56,10 @@ description: This is meant to help facilitate an API-first strategy when creatin
56
56
  web apps with RoR
57
57
  email:
58
58
  - micah.shute@gmail.com
59
- executables: []
59
+ executables:
60
+ - console
61
+ - local_model
62
+ - setup
60
63
  extensions: []
61
64
  extra_rdoc_files: []
62
65
  files:
@@ -70,6 +73,7 @@ files:
70
73
  - README.md
71
74
  - Rakefile
72
75
  - bin/console
76
+ - bin/local_model
73
77
  - bin/setup
74
78
  - lib/local_model.rb
75
79
  - lib/local_model/adapters/boolean_adapter.rb
@@ -82,10 +86,14 @@ files:
82
86
  - lib/local_model/csv.rb
83
87
  - lib/local_model/errors/record_invalid.rb
84
88
  - lib/local_model/errors/record_not_found.rb
89
+ - lib/local_model/generators/initialize.rb
85
90
  - lib/local_model/helpers/functions.rb
86
91
  - lib/local_model/helpers/pluralized_words.rb
87
92
  - lib/local_model/model.rb
88
93
  - lib/local_model/sandbox.rb
94
+ - lib/local_model/templates/data_accessor.erb
95
+ - lib/local_model/templates/generate_model.erb
96
+ - lib/local_model/templates/initializer.erb
89
97
  - lib/local_model/version.rb
90
98
  - local_model.gemspec
91
99
  homepage: https://github.com/micahshute/local_model