Module: Enginery::Helpers

Includes:
EUtils
Included in:
Configurator, Delete, Generator, Migrator, Registry
Defined in:
lib/enginery/helpers/app.rb,
lib/enginery/helpers/orm.rb,
lib/enginery/helpers/input.rb,
lib/enginery/helpers/generic.rb,
lib/enginery/helpers/validations.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extract_setup(input) ⇒ Object



117
118
119
# File 'lib/enginery/helpers/input.rb', line 117

def extract_setup input
  input.scan(/:(.+)/).flatten.last
end

.fail(*failures) ⇒ Object



12
13
14
# File 'lib/enginery/helpers/validations.rb', line 12

def fail *failures
  throw :enginery_failures, Failure.new(*failures)
end

.fail_verbosely(*failures) ⇒ Object



17
18
19
20
# File 'lib/enginery/helpers/validations.rb', line 17

def fail_verbosely *failures
  o *failures
  fail *failures
end

.o(*chunks) ⇒ Object



93
94
95
96
97
# File 'lib/enginery/helpers/generic.rb', line 93

def o *chunks
  @logger ||= Logger.new(STDOUT)
  opts = chunks.last.is_a?(Hash) ? chunks.pop : {}
  @logger << "%s\n" % chunks.join(opts[:join].to_s)
end

.parse_input(*input) ⇒ Object

TODO: refactor this huge method



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/enginery/helpers/input.rb', line 5

def parse_input *input
  input.flatten!
  args, setups, string_setups = [], {}, []
  input.each do |a|
    case

    # generator
    when a =~ /\Ao(rm)?:/
      orm = extract_setup(a)
      if valid_orm = valid_orm?(orm)
        setups[:orm] = valid_orm
        string_setups << a
      else
        fail_verbosely 'Invalid ORM provided - "%s"' % orm, \
          'Supported ORMs: ActiveRecord, DataMapper, Sequel'
      end
    when a =~ /\Ae(ngine)?:/
      smth = extract_setup(a)
      if engine = valid_engine?(smth)
        setups[:engine] = engine
        string_setups << a
      else
        fail_verbosely 'Invalid engine provided - %s' % smth, \
          'Supported engines(Case Sensitive): %s' % EConstants::VIEW__ENGINE_BY_SYM.keys.join(', ')
      end
    when a =~ /\Af(ormat|ile)?:/
      if format = extract_setup(a)
        # format if used by generator, file is used by migrator
        setups[:format] = setups[:file] = format
        string_setups << a
      end
    when a =~ /\Ar(oute)?:/
      if route = extract_setup(a)
        setups[:route] = route
        string_setups << a
      end
    when a =~ /\Adb/
      [:type, :host, :port, :name, :user, :pass].each do |s|
        if (a =~ /\Adb(_)?#{s}:/) && (v = extract_setup(a))
          (setups[:db] ||= {}).update s => (s == :type ? valid_db_type?(v) : v)
          string_setups << a
        end
      end
    when a =~ /\As(erver)?:/
      smth = extract_setup(a)
      if server = valid_server?(smth)
        setups[:server] = server.to_sym
        string_setups << a
      else
        fail_verbosely 'Unknown server provided - %s' % smth, \
          'It wont be added to Gemfile nor to config.yml', \
          'Known servers(Case Sensitive): %s' % KNOWN_WEB_SERVERS.join(', ')
      end
    when a =~ /\Ap(ort)?:/
      smth = extract_setup(a)
      if (port = smth.to_i) > 0
        setups[:port] = port
        string_setups << a
      else
        fail_verbosely 'Invalid port provided - %s' % smth, 'Port should be a number'
      end
    when a =~ /\Ah(ost(s)?)?:/
      if hosts = extract_setup(a)
        setups[:hosts] = hosts.split(',')
        string_setups << a
      end
    when a =~ /\Ai(nclude)?:/
      mdl = validate_constant_name extract_setup(a)
      (setups[:include] ||= []).push mdl
      string_setups << a

    # migrator
    when a =~ /\Acreate_table_for:/
      if table = extract_setup(a)
        setups[:create_table] = table
        string_setups << a
      end
    when a =~ /\Am(odel)?:/
      if table = extract_setup(a)
        setups[:update_table] = table
        string_setups << a
      end
    when a =~ /\Aa?(dd_)?c(olumn)?:/
      if column = extract_setup(a)
        (setups[:create_columns] ||= []).push column.split(':')
        string_setups << a
      end
    when a =~ /\Au(pdate_)?c?(olumn)?:/
      if column = extract_setup(a)
        (setups[:update_columns] ||= []).push column.split(':')
        string_setups << a
      end
    when a =~ /\Ar(ename_)?c?(olumn)?:/
      if column = extract_setup(a)
        (setups[:rename_columns] ||= []).push column.split(':')
        string_setups << a
      end
    else
      args.push(a) unless ORM_ASSOCIATIONS.find {|an| a =~ /#{an}/}
    end
  end
  ORM_ASSOCIATIONS.each do |a|
    input.select {|x| x =~ /\A#{a}:/}.each do |s|
      next unless v = extract_setup(s)
      (setups[a] ||= []).push v
      string_setups << s
    end
  end
  [args.freeze, setups.freeze, string_setups.join(' ').freeze]
end

.valid_db_type?(smth) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
45
46
47
48
49
50
51
52
# File 'lib/enginery/helpers/validations.rb', line 42

def valid_db_type? smth
  return unless  smth.is_a?(String) || smth.is_a?(Symbol)
  case
  when smth =~ /\Am/i
    :mysql
  when smth =~ /\Ap/i
    :postgres
  when smth =~ /\As/i
    :sqlite
  end
end

.valid_engine?(smth) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
58
# File 'lib/enginery/helpers/validations.rb', line 55

def valid_engine? smth
  engine = smth.to_s.to_sym
  EConstants::VIEW__ENGINE_BY_SYM.has_key?(engine) ? engine : false
end

.valid_orm?(smth) ⇒ Boolean

Returns:

  • (Boolean)


29
30
31
32
33
34
35
36
37
38
39
# File 'lib/enginery/helpers/validations.rb', line 29

def valid_orm? smth
  return unless smth.is_a?(String) || smth.is_a?(Symbol)
  case
  when smth =~ /\Aa/i
    :ActiveRecord
  when smth =~ /\Ad/i
    :DataMapper
  when smth =~ /\As/i
    :Sequel
  end
end

.valid_server?(smth) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
26
# File 'lib/enginery/helpers/validations.rb', line 23

def valid_server? smth
  server = smth.to_s.to_sym
  KNOWN_WEB_SERVERS.include?(server) ? server : false
end

.validate_constant_name(constant) ⇒ Object



86
87
88
89
90
91
# File 'lib/enginery/helpers/validations.rb', line 86

def validate_constant_name constant
  constant =~ /[^\w|\d|\:]/ && fail("Wrong constant name - %s, it should contain only alphanumerics" % constant)
  constant =~ /\A[0-9]/     && fail("Wrong constant name - %s, it should start with a letter" % constant)
  constant =~ /\A[A-Z]/     || fail("Wrong constant name - %s, it should start with a uppercase letter" % constant)
  constant
end

Instance Method Details

#activerecord_associations(setups = {}) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/enginery/helpers/orm.rb', line 4

def activerecord_associations setups = {}
  ORM_ASSOCIATIONS.inject([]) do |lines,a|
    (setups[a]||[]).each do |s|
      line, input = nil, s.split(':')
      target = input[0]
      if target =~ /\W/
        o '*** WARN: invalid association target "%s", association not added ***' % target
      else
        line = '%s :%s' % [a, target]
        if through = input[1].to_s =~ /through/ && input[2]
          if through =~ /\W/
            o '*** WARN: invalid :through option "%s", association not added ***' % through
            line = nil
          else
            line << ', through: :%s' % through
          end
        end
      end
      lines.push(line) if line
    end
    lines
  end
end

#app_configObject



70
71
72
73
74
75
76
# File 'lib/enginery/helpers/app.rb', line 70

def app_config
  pv, $VERBOSE = $VERBOSE, nil
  load dst_path.config_rb
  Cfg
ensure
  $VERBOSE = pv
end

#app_controllersObject



21
22
23
# File 'lib/enginery/helpers/app.rb', line 21

def app_controllers
  App.mounted_controllers.select {|c| controller_exists?(c.name)}
end

#app_modelsObject



41
42
43
44
45
46
47
48
# File 'lib/enginery/helpers/app.rb', line 41

def app_models
  load_boot_rb
  identity_methods = ORM_IDENTITY_METHODS[Cfg[:orm].to_s.to_sym]
  return [] unless identity_methods
  ObjectSpace.each_object(Class).select do |o|
    identity_methods.all? {|m| o.respond_to?(m)} && model_exists?(o.name)
  end
end

#boot_appObject



16
17
18
19
# File 'lib/enginery/helpers/app.rb', line 16

def boot_app
  load_boot_rb
  App.boot!
end

#controller_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
# File 'lib/enginery/helpers/app.rb', line 31

def controller_exists? name
  path = dst_path(:controllers, class_to_route(name))
  File.file?(path + CONTROLLER_SUFFIX) && path
end

#datamapper_associations(setups = {}) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/enginery/helpers/orm.rb', line 28

def datamapper_associations setups = {}
  ORM_ASSOCIATIONS.inject([]) do |lines,a|
    (setups[a]||[]).each do |s|
      line, input = nil, s.split(':')
      target = input[0]
      if target =~ /\W/
        o '*** WARN: invalid association target "%s", association not added ***' % target
      else
        if a == :has_one
          line = 'has 1, :%s' % target
        elsif a =~ /has_(and|many)/
          line = 'has n, :%s' % target
        else
          line = '%s :%s' % [a, target]
        end
        if through = input[1].to_s =~ /through/ && input[2]
          if through =~ /\W/
            o '*** WARN: invalid :through option "%s", association not added ***' % through
            line = nil
          else
            line << ', through: :%s' % through
          end
        end
      end
      lines.push(line) if line
    end
    lines
  end
end

#dst_path(*args) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/enginery/helpers/generic.rb', line 35

def dst_path *args
  @dst_path_map ||= begin
    paths = { :root => @dst_root.to_s.gsub(/\/+/, '/') }
    [
      :base,
      :config,
    ].each {|p| paths[p] = File.join(paths[:root], p.to_s, '')}
    [
      :controllers,
      :models,
      :views,
      :specs,
      :migrations,
      :helpers
    ].each {|d| paths[d] = File.join(paths[:base], d.to_s, '')}

    paths[:rear_controllers] = File.join(paths[:controllers], 'rear-controllers', '')
    paths[:config_rb] = File.join(paths[:base], 'config.rb')
    paths[:config_yml] = File.join(paths[:config], 'config.yml')
    paths[:database_yml] = File.join(paths[:config], 'database.yml')
    
    [
      :Rakefile,
      :Gemfile,
    ].each {|f| paths[f] = File.join(paths[:root], f.to_s)}
    [
      :boot_rb,
      :database_rb,
    ].each {|f| paths[f] = File.join(paths[:base], f.to_s.sub('_rb', '.rb'))}
    paths.values.map(&:freeze)
    [paths, Struct.new(*paths.keys).new(*paths.values)]
  end
  paths, struct = @dst_path_map
  return struct if args.empty?
  
  paths[args.first] || fail('%s is not a recognized destination path.
    Use one of %s' % [args.first.inspect, paths.map(&:inspect)*', '])
  File.join(paths[args.shift], *args.map(&:to_s)).gsub(/\/+/, '/').freeze
end

#fail_unless_in_app_folder!Object



8
9
10
# File 'lib/enginery/helpers/validations.rb', line 8

def fail_unless_in_app_folder!
  in_app_folder? || fail("Seems current folder does not contain a Espresso application")
end

#in_app_folder?Boolean

Returns:

  • (Boolean)


4
5
6
# File 'lib/enginery/helpers/validations.rb', line 4

def in_app_folder?
  File.directory?(dst_path.controllers)
end

#load_boot_rbObject



4
5
6
7
8
9
10
11
12
13
14
# File 'lib/enginery/helpers/app.rb', line 4

def load_boot_rb
  pv, $VERBOSE = $VERBOSE, nil
  orig = Array.new($:)
  # loading app
  load dst_path.boot_rb
  # for some reason, Bundler get rid of existing loadpath entries.
  # usually this will break autoloading, so storing orig paths and inserting them back
  orig.each {|p| $:.include?(p) || $: << p}
ensure
  $VERBOSE = pv
end

#migrations_by_model(model) ⇒ Object



50
51
52
53
54
# File 'lib/enginery/helpers/app.rb', line 50

def migrations_by_model model
  Dir[dst_path(:migrations, class_to_route(model), '*' + MIGRATION_SUFFIX)].map do |f|
    File.basename(f)
  end
end

#model_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


36
37
38
39
# File 'lib/enginery/helpers/app.rb', line 36

def model_exists? name
  path = dst_path(:models, class_to_route(name))
  File.file?(path + MODEL_SUFFIX) && path
end

#routes_by_controller(controller) ⇒ Object



25
26
27
28
29
# File 'lib/enginery/helpers/app.rb', line 25

def routes_by_controller controller
  Dir[dst_path(:controllers, class_to_route(controller), '*' + ROUTE_SUFFIX)].map do |f|
    File.basename(f, File.extname(f))
  end
end

#sequel_associations(setups = {}) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/enginery/helpers/orm.rb', line 58

def sequel_associations setups = {}
  ORM_ASSOCIATIONS.inject([]) do |lines,a|
    (setups[a]||[]).each do |s|
      line, input = nil, s.split(':')
      target = input[0]
      if target =~ /\W/
        o '*** WARN: invalid association target "%s", association not added ***' % target
      else
        case a
        when :belongs_to
          line = 'many_to_one :%s' % target
        when :has_one
          line = 'one_to_one :%s' % target
        when :has_many
          line = 'one_to_many :%s' % target
        when :has_and_belongs_to_many
          line = 'many_to_many :%s' % target
        end
        if through = input[1].to_s =~ /through/ && input[2]
          o '*** INFO: Sequel does not support :through option, ignoring ***' % through
        end
      end
      lines.push(line) if line
    end
    lines
  end
end

#src_path(*args) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/enginery/helpers/generic.rb', line 12

def src_path *args
  @src_path_map ||= begin
    paths = { :root => File.expand_path('../../../../app', __FILE__) + '/' }
    [
      :base,
      :gemfiles,
      :rakefiles,
      :specfiles,
      :database,
      :migrations,
      :layouts,
    ].each {|d| paths[d] = File.join(paths[:root], d.to_s, '')}
    paths.values.map(&:freeze)
    [paths, Struct.new(*paths.keys).new(*paths.values)]
  end
  paths, struct = @src_path_map
  return struct if  args.empty?
  
  paths[args.first] || fail('%s is not a recognized source path.
    Use one of %s' % [args.first.inspect, paths.map(&:inspect)*', '])
  File.join(paths[args.shift], *args.map(&:to_s)).gsub(/\/+/, '/').freeze
end

#unrootify(path, root = nil) ⇒ Object



75
76
77
78
79
# File 'lib/enginery/helpers/generic.rb', line 75

def unrootify path, root = nil
  root = (root || dst_path.root).gsub(/\/+/, '/')
  regexp = /\A#{Regexp.escape(root)}\/?/
  path.gsub(/\/+/, '/').sub(regexp, '')
end

#valid_controller?(name) ⇒ Boolean

Returns:

  • (Boolean)


61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/enginery/helpers/validations.rb', line 61

def valid_controller? name
  name.nil? || name.empty? && fail("Please provide controller name")
  ctrl_path = controller_exists?(name) || fail('"%s" controller does not exists' % name)

  ctrl = name.split('::').map(&:to_sym).inject(Object) do |ns,c|
    ctrl_dirname = unrootify(ctrl_path)
    ns.const_defined?(c) || fail("#{ctrl_dirname} exists but #{name} controller not defined.
      Please define it manually or delete #{ctrl_dirname} and start over.")
    ns.const_get(c)
  end
  [ctrl_path, ctrl]
end

#valid_route?(ctrl_name, name) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
82
83
84
# File 'lib/enginery/helpers/validations.rb', line 74

def valid_route? ctrl_name, name
  ctrl_path, ctrl = valid_controller?(ctrl_name)
  name.nil? || name.empty? && fail("Please provide route name")
  path_rules = ctrl.path_rules.inject({}) do |map,(r,s)|
    map.merge %r[#{Regexp.escape s}] => r.source
  end
  route = action_to_route(name, path_rules)
  validate_route_name(route)
  file = File.join(ctrl_path, route + '.rb')
  [file, route]
end

#validate_route_name(name) ⇒ Object



94
95
96
97
# File 'lib/enginery/helpers/validations.rb', line 94

def validate_route_name name
  name =~ /\W/ && fail("Routes may contain only alphanumerics")
  name
end

#view_setups_for(ctrl, action) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/enginery/helpers/app.rb', line 56

def view_setups_for ctrl, action
  boot_app
  ctrl_instance = ctrl.new
  ctrl_instance.respond_to?(action.to_sym) || fail('"%s" route does not exists' % action)
  
  action_name, request_method = deRESTify_action(action)
  ctrl_instance.action_setup  = ctrl.action_setup[action_name][request_method]
  ctrl_instance.call_setups!
  [
    File.join(ctrl_instance.view_path?, ctrl_instance.view_prefix?),
    ctrl_instance.engine_ext?
  ]
end