I am trying to separate files in an Elm project, as keeping everything in global Model, Messages, etc. would be just a mess.
Here is how I tried it so far:
So, there are some global files, and then Header has its own files. However I keep getting error, when importing Header.View into my global View:
The 1st and 2nd entries in this list are different types of values.
Which kind of makes sense:
The 1st entry has this type:
Html Header.Messages.Msg
But the 2nd is:
Html Msg
So, my question is whether all the messages (from all my modules, like Header) needs to be combined somehow in global Messages.elm? Or there is a better way of doing this?
My advice would be to keep messages and update in 1 file until that feels uncomfortable (for you to decide how many lines of code that means - see Evan's Elm Europe talk for more on the modules flow). When you want to break something out, define a new message in Main
type Msg
= HeaderMsg Header.Msg
| ....
Then use Cmd.map HeaderMsg in your update function and Html.map HeaderMsg in your view function to connect up your sub-components
Related
I have some records in a CMS that include HTML fragments with custom tags for a widget tool. The maker of the CMS has apparently updated their CMS without providing proper data conversion. Their widgets use keys for layout based on screen width such as block_lg, block_md, block_sm. The problem kicks in with the fact they used to have a block_xs and they have now shifted them all -- dropping the block_xs and instead placing a block_xl on the other end.
We don't really use these things, but their widget configurations do. What this means for us is the values for each key are identical. The problem occurs when the updated CMS code is looking for the 'block_xl' in any widget definition tags, it can't find it and errors out.
What I'm thinking then is that the new code will appear to 'ignore' the block_xs due to how it reads the tags. (and similarly, the old code will ignore block_xl) Since the values for each are identical, I need to basically read any widget definition and add a block_xl value to it matching the value of [any one of] the other width parameters.
Since the best place order-wise would be 'before' the block_lg value, it's probably easiest to do it as follows:
Replace any thing matching posix style regex matching /block_lg(="\d+,\d+")/ with: block_xl="$1" block_lg="$1"
Or whatever the equivalent of that would be.
Example of an existing CMS block with multiple widget definitions:
<div>{{widget type="CleverSoft\CleverBlock\Block\Widget"
widget_title="The Album" classes="highlight-bottom modish greenfont font52 fontlight"
enable_fullwidth="0" block_ids="127" lazyload="0"
block_lg="127,12," block_md="127,12," block_sm="127,12," block_xs="127,12,"
template="widget/block.phtml" scroll="0" background_overlay_o="0"}}</div>
<!-- Image Block -->
<div>{{widget type="CleverSoft\CleverBlock\Block\Widget"
widget_title="What’s Your Favorite Cover Style?"
classes="zoo-widget-style2 modish grey font26 fontlight"
enable_fullwidth="0" block_ids="126" lazyload="0"
block_lg="126,12," block_md="126,12," block_sm="126,12," block_xs="126,12,"
template="widget/block.phtml" scroll="0" background_overlay_o="0"}}</div>
What I would prefer to end up with from the above (adding block_xl):
<div>{{widget type="CleverSoft\CleverBlock\Block\Widget"
widget_title="The Album" classes="highlight-bottom modish greenfont font52 fontlight"
enable_fullwidth="0" block_ids="127" lazyload="0"
block_xl="127,12," block_lg="127,12," block_md="127,12," block_sm="127,12," block_xs="127,12,"
template="widget/block.phtml" scroll="0" background_overlay_o="0"}}</div>
<!-- Image Block -->
<div>{{widget type="CleverSoft\CleverBlock\Block\Widget"
widget_title="What’s Your Favorite Cover Style?"
classes="zoo-widget-style2 modish grey font26 fontlight"
enable_fullwidth="0" block_ids="126" lazyload="0"
block_xl="126,12," block_lg="126,12," block_md="126,12," block_sm="126,12," block_xs="126,12,"
template="widget/block.phtml" scroll="0" background_overlay_o="0"}}</div>
I know how to do it in php and if necessary, I will just replace it on my local DB and write an sql script to update the modified records, but the html blocks can be kind of big in some cases. It would be preferable, if it is possible, to make the substitutions right in the SQL but I'm not sure how to do it or if it's even possible to do.
And yes, there can be more than one instance of a widget in any given cms page or block. (i.e. there may be a need for more than one such substitutions with different local 'values' assigned to the block_lg)
If anyone can help me do it in SQL, it would be greatly appreciated.
for reference, the tables effected are called cms_page and cms_block, the name of the row in both cases is content
SW
Suppose I want to create a webpage with two components, say a Navbar and a Body. These two components do not interact with each other and can be developed independently. So, I have two elm files which have the following components in each of them:
type Model = ...
type Msg = ...
init : (Model, Cmd Msg)
update : Msg -> Model -> (Model, Cmd Msg)
view : Model -> Html Msg
Assumming that they both work fine, how do we compose them to make a program which has both these components?
I tried writing something like this:
type Model = {body : Body.Model , navbar : Navbar.Model}
type Msg = BodyMsg Body.Msg | NavbarMsg Navbar.Msg
view : Model -> Html Msg
view model = div [] [Body.view model.body, Navbar.view model.navbar]
update : Msg -> Model -> (Model, Cmd Msg)
update = ...
The above gets ugly quickly when I try to write this update function. In particular, once I extract the Msg's out of the Cmd's update functions from Navbar.update or Body.update, how do I extract them and feed them back to these functions again? Also, the view function above does not particularly look idiomatic.
What is the elm-architecture recommended way to solve this problem? Is this pattern idiomatic in elm-architecture?
I think #dwaynecrooks covered the technical aspects of the question. But I believe your problem implies a design aspect too.
How to grow Elm code?
As others pointed out: thinking in terms of components will almost certainly take you down a not so appealing path with Elm. (Many people start there. I and my team started there over 2 years ago, and it took us 3 apps/major redesigns to get to a point where I think we can be happy at least about the fundamentals.)
Instead of components, I suggest you should think of your Elm application as a tree. Each node of your tree represents a level of abstraction, and describes the behavior of your application on that level. When you have the feeling that there is too much detail for a given level, you can start thinking about how new, lower levels of abstraction could be introduced as child nodes.
In practice each node is implemented in its own Elm module: parents import their children. You may also consider that you don't have to stick to the usual model/update/view signatures, rather you should focus on the particularities of your app's domain. This is what – in my read – Richard Feldman is doing in his Real World SPA example app. And Evan's Life of a file talk is related to this question too.
The case of navbar + body
Regarding your particular case – it is not a rare case – here is my experience. If we say that our webapp has a navbar and then some body, this is a pretty static description of the app. This kind of description may fit a component based thinking, but it is less helpful if you want to end up with an elegant Elm app.
Instead, it is worth trying to describe the behavior of your app at this level of abstraction, which may sound something like this: The user can select x,y,z items in a navbar. Clicking on those items will affect the item in q way and also affect the body in either a, or b way. He can also click on v in the navbar, which would show a popup or do w, which logs him out of the app.
If you take this description and apply the logic that I described above, you should probably end up with some sort of a design where most of your navbar is described in your highest level of abstraction. This includes items x, y, z, v and behaviors a, b, w. Now, behavior a may mean that a specific, rich page must be displayed, which has its own detailed behavior that is described on a lower level of abstraction, whereas behavior b may mean that based on the selection some content must be loaded, and again the details of this loading process is worked out on a lower level of abstraction. And so on.
When we started approaching the problem this way, it became much more straight forward to find out how to split up logic, and how to deal with special cases.
We realized, for instance, that when someone said that a page wants to display some stuff "in the navbar", what she really meant was that the navbar should collapse (or transform) for a particular page so that page can display it's own header in that area.
Focusing on the app's behavior instead of static content areas helped with this.
Yes, you're on the right path.
In the view you need to use Html.map.
view : Model -> Html Msg
view model =
div []
[ Html.map BodyMsg (Body.view model.body)
, Html.map NavbarMsg (Navbar.view model.navbar)
]
Body.view model.body has type Html Body.Msg which requires us to use Html.map to get the correct type of Html Msg. Similarly for Navbar.view model.navbar.
And, for the update function you'd write it like so:
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
BodyMsg bodyMsg ->
let
(newBody, newCmd) = Body.update bodyMsg model.body
in
{ model | body = newBody } ! [ Cmd.map BodyMsg newCmd ]
NavbarMsg navbarMsg ->
let
(newNavbar, newCmd) = Navbar.update navbarMsg model.navbar
in
{ model | navbar = newNavbar } ! [ Cmd.map NavbarMsg newCmd ]
In the BodyMsg case, newBody has type Body.Model and so we can set the body field in model to it. However, newCmd has type Cmd Body.Msg and so before we can return we need to use Cmd.map to get the correct return type of Cmd Msg.
Similar reasoning can be used for the NavbarMsg case.
Also, the view function above does not particularly look idiomatic.
What bothers you about the view code?
N.B. This answer assumes you're using Elm 0.18.
That's basically the way to go, yes. There is a popular example for a larger SPA in Elm on GitHub. Here can you see the Main.elm that takes care of mapping the messages from each page: https://github.com/rtfeldman/elm-spa-example/blob/master/src/Main.elm
One thing that is missing from your example is the mapping of the message type that is absolutly required. I guess you left that out to have a smaller post, but from my experience that is the actual part where the boilerplate comes in.
However, you should try not to emulate a component approach like React. Just use functions. Separate pages in an SPA are one example where it makes sense to have a dedicatated message type and corresponding functions like you would with a program.
This article explains the general approach of scaling a larger Elm app and also mentions the point about not having dedicated messages for each component.
I have a content directory called foo and I want all files under that directory to have an extra metadata item foovar: default, unless explicitly overridden in the file header. I think I'm supposed to do this with EXTRA_PATH_METADATA, but I can't figure out what incantation it wants.
(for my current use case I'm trying to apply template: sometemplate within this dir, but I'm interested in solving the general case as it would make several related headaches go away)
I think what you're looking for is actually DEFAULT_METADATA. Check out this portion of the documentation:
DEFAULT_METADATA = {}
The default metadata you want to use for all articles and pages.
So, in your case it might look something like this in your config file:
DEFAULT_METADATA = {'foovar': 'default'}
Then to assign your custom template(s), see this portion of the documentation.
This wasn't possible at the time I asked. I've since sent the devs a PR adding support, and it's been merged to master. Presumably it will go out in the next release. It makes EXTRA_PATH_METADATA recursive, so you can apply settings to a subdir like this:
EXTRA_PATH_METADATA = {'dirname/subdir': {'status': 'hidden'}}
In my project Mockito.times(1) is often used when verifying mocks:
verify(mock, times(1)).call();
This is redundant since Mockito uses implicit times(1) for verify(Object), thus the following code does exactly what the code above does:
verify(mock).call();
So I'm going to write an a structural search drive inspection to report such cases (let's say, named something like Mockito.times(1) is redundant). As I'm not an expert in IntelliJ IDEA structural search, my first attempt was:
Mockito.times(1)
Obviously, this is not a good seach template because it ignores the call-site. Let's say, I find it useful for the following code and I would not like the inspection to trigger:
VerificationMode times = Mockito.times(1);
// ^ unwanted "Mockito.times(1) is redundant"
So now I would like to define the context where I would like the inspection to trigger. Now the inspection search template becomes:
Mockito.verify($mock$, Mockito.times(1))
Great! Now code like verify(mock, times(1)).call() is reported fine (if times was statically imported from org.mockito.Mockito). But there is also one thing. Mockito.times actually comes from its VerificationModeFactory class where such verification modes are grouped, so the following line is ignored by the inspection:
verify(mockSupplier, VerificationModeFactory.times(1)).get();
My another attempt to fix this one was something like:
Mockito.verify($mock$, $times$(1))
where:
$mock$ is still a default template variable;
$times$ is a variable with Text/regexp set to times, Whole words only and Value is read are set to true, and Expression type (regexp) is set to (Times|VerificationMode) -- at least this is the way I believed it should work.
Can't make it work. Why is Times also included to the regexp? This is the real implementation of *.times(int), so, ideally, the following line should be reported too:
verify(mockSupplier, new Times(1)).get();
Of course, I could create all three inspection templates, but is it possible to create such a template using single search template and what am I missing when configuring the $times$ variable?
(I'm using IntelliJ IDEA Community Edition 2016.1.1)
Try the following search query:
Mockito.verify($mock$, $Qualifier$.times(1))
With $Qualifier$ text/regexp VerificationModeFactory|Mockito and occurrences count 0,1 (to find it when statically imported also).
To also match new Times(1) you can use the following query:
Mockito.verify($mock$, $times$)
With $times$ text/regexp .*times\s*\(\s*1\s*\) and uncheck the Case sensitive checkbox.
I'm using cvs2svn to convert my repository. I've done it with success in one repository, and now my new problem is a second repository.
In my new conversion, I want to convert only the HEAD and one branch. cvs2svn only have "exclude" function for branches, but not "include". I have many many branches and excluding each and every one of them will take A LOT of work....
is there any way to convert only the trunk (HEAD) and only one branch?
thanks,
Oded
If you only want to retain the one branch and no tags, then this is easy. The first rule that matches a symbol is used, so specify the branch that you want to be included then exclude everything else:
cvs2svn --force-branch=mybranch --exclude='.*' ...
If you want to include not only the branch but also as many tags as possible, then it is a little bit trickier. Not only don't you necessarily know the names of all of the tags, but you also cannot include tags that are dependent on excluded branches. In this case, it is easiest to work with the --write-symbol-info and --symbol-hints options:
cvs2svn --write-symbol-info=symbol-info.out --passes=1:3 ...
This will create a file called "symbol-info.out" containing information about all CVS symbols. In your editor, open this file, find all of the lines corresponding to branches that you want to exclude, and change the third column of those lines to the word "exclude". Make sure that the third column of the line for the branch that you want to include contains the word "branch" and its fourth column is the path where you want it to end up.
Now run cvs2svn again, starting at pass 3, and using the edited symbol-info file as a symbol hints file:
cvs2svn --symbol-hints=symbol-info.out --passes=3 ...
you will get a lot of errors like:
ERROR: ExcludedSymbol('FOO_BRANCH') cannot be excluded because the following symbols depend on it:
BAR_TAG
BAZ_TAG
Now go back into the editor and change the listed tags (BAR_TAG and BAZ_TAG in the example) to be excluded too, then try running pass3 again. This procedure might need to be iterated a couple of times, but it should not be cumbersome because pass3 runs very quickly.
When you have gotten pass3 to complete without errors, run the rest of the conversion:
cvs2svn --symbol-hints=symbol-info.out --passes=4: ...
One problem is that cvs2svn not only needs to determine whether to include a branch or not, but (simultaneously) whether a symbol is a branch or a tag in the first place. So if you want to include that one branch, and also some tags, it's more difficult than just saying "include only that branch" - doing so would kill all tags.
IOW, cvs2svn doesn't really support that. You can work around by editing its source code. In cvs2svn_lib.symbol_strategy.BranchIfCommits, change the case where it returns Branch(symbol) to
if symbol.name == 'my_branch':
return Branch(symbol)
else:
return ExcludedSymbol(symbol)
IIUC, BranchIfCommits should be used by default.
Personally, I would use a different strategy:
1. convert the repository once, with all branches.
2. do a "svn ls" on branches, and redirect that into a file.
3. edit the file to construct an exclude regex out of it, of the form `b1|b2|...|bn`
I wouldn't call that a LOT of work...